@@ -2405,6 +2405,7 @@ It is worth mentioning some resources to help you get started:
2405
2405
- Marius Schultz: https://blog.mariusschulz.com/series/typescript-evolution with an [Egghead.io course](https://egghead.io/courses/advanced-static-types-in-typescript)
2406
2406
- Basarat's Deep Dive: https://basarat.gitbook.io/typescript/
2407
2407
- Rares Matei: [Egghead.io course](https://egghead.io/courses/practical-advanced-typescript)'s advanced TypeScript course on Egghead.io is great for newer typescript features and practical type logic applications (e.g. recursively making all properties of a type `readonly`)
2408
+
- Go through [Remo Jansen's TypeScript ladder](http://www.techladder.io/?tech=typescript)
2408
2409
- Shu Uesugi: [TypeScript for Beginner Programmers](https://ts.chibicode.com/)
2409
2410
2410
2411
<!--END-SECTION:learn-ts-->
Original file line number
Diff line number
Diff line change
@@ -315,6 +315,24 @@ type NumbersChildren = number[];
315
315
typeTwoNumbersChildren= [number, number];
316
316
```
317
317
318
+
<details>
319
+
<summary>
320
+
Don't forget that you can also use `prop-types` if TS fails you.
321
+
</summary>
322
+
323
+
```ts
324
+
Parent.propTypes= {
325
+
children: PropTypes.shape({
326
+
props: PropTypes.shape({
327
+
// could share `propTypes` to the child
328
+
value: PropTypes.string.isRequired,
329
+
}),
330
+
}).isRequired,
331
+
};
332
+
```
333
+
334
+
</details>
335
+
318
336
### What You CANNOT Do
319
337
320
338
The thing you cannot do is **specify which components** the children are, e.g. If you want to express the fact that "React Router `<Routes>` can only have `<Route>` as children, nothing else is allowed" in TypeScript.
@@ -125,7 +125,7 @@ export class MyComponent extends React.Component<IMyComponentProps> {
125
125
126
126
The problem with this approach is it causes complex issues with the type inference working with `JSX.LibraryManagedAttributes`. Basically it causes the compiler to think that when creating a JSX expression with that component, that all of its props are optional.
127
127
128
-
[See commentary by @ferdaber here](https://.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/57).
128
+
[See commentary by @ferdaber here](https://.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/57) and [here](https://.com/typescript-cheatsheets/react/issues/61).
129
129
130
130
</details>
131
131
Original file line number
Diff line number
Diff line change
@@ -5,7 +5,7 @@ title: Hooks
5
5
6
6
Hooks are [supported in `@types/react` from v16.8 up](https://.com/DefinitelyTyped/DefinitelyTyped/blob/a05cc538a42243c632f054e42eab483ebf1560ab/types/react/index.d.ts#L800-L1031).
When using `useRef`, you have two options when creating a ref container that does not have an initial value:
29
+
You can use [Discriminated Unions](https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions) for reducer actions. Don't forget to define the return type of reducer, otherwise TypeScript will infer it.
30
30
31
-
```ts
32
-
const ref1 =useRef<HTMLElement>(null!);
33
-
const ref2 =useRef<HTMLElement|null>(null);
31
+
```tsx
32
+
typeAppState= {};
33
+
typeAction=
34
+
| { type:"SET_ONE"; payload:string } // typescript union types allow for leading |'s to have nicer layout
The first option will make `ref1.current` read-only, and is intended to be passed in to built-in `ref` attributes that React will manage (because React handles setting the `current` value for you).
55
+
[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/C4TwDgpgBAgmYGVgENjQLxQN4F8CwAUKJLAMbACWA9gHZTqFRQA+2UxEAXFAEQICiAFQD6AeQBy-HgG4oYZCAA2VZABNuAZ2AAnCjQDmUfASass7cF14CRggOqiZchcrXcaAVwC2AIwjajaUJCCAAPMCptYCgAMw8acmo6bQhVD1J-AAotVCs4RBQ0ABooZETabhhymgBKSvgkXOxGKA0AdwpgUgALKEyyyloAOg4a5pMmKFJkDWg+ITFJHk4WyagU4A9tOixVtaghw5zivbXaKwGkofklFVUoAHoHqAADG9dVF6gKDVadPX0p0Ce2ms2sC3sjhWEzWGy2OyBTEOQ2OECKiPYbSo3Euw3ed0ezzeLjuXx+UE8vn8QJwQRhUFUEBiyA8imA0P26wgm22f1ydKYxhwQA)
37
56
38
57
<details>
39
-
<summary>What is the <code>!</code> at the end of <code>null!</code>?</summary>
40
58
41
-
`null!` is a non-null assertion operator (the `!`). It asserts that any expression before it is not `null` or `undefined`, so if you have `useRef<HTMLElement>(null!)` it means that you're instantiating the ref with a current value of `null` but lying to TypeScript that it's not `null`.
59
+
<summary><b>Usage with `Reducer` from `redux`</b></summary>
42
60
43
-
```ts
44
-
function MyComponent() {
45
-
const ref1 =useRef<HTMLElement>(null!);
46
-
useEffect(() => {
47
-
doSomethingWith(ref1.current); // TypeScript won't require null-check e.g. ref1 && ref1.current
48
-
});
49
-
return <divref={ref1}> etc</div>;
50
-
}
61
+
In case you use the [redux](https://.com/reduxjs/redux) library to write reducer function, It provides a convenient helper of the format `Reducer<State, Action>` which takes care of the return type for you.
The second option will make `ref2.current` mutable, and is intended for "instance variables" that you manage yourself.
56
-
57
-
**useEffect**
73
+
## useEffect
58
74
59
75
When using `useEffect`, take care not to return anything other than a function or `undefined`, otherwise both TypeScript and React will yell at you. This can be subtle when using arrow functions:
60
76
@@ -73,7 +89,35 @@ function DelayedEffect(props: { timerMs: number }) {
73
89
}
74
90
```
75
91
76
-
**useRef**
92
+
## useRef
93
+
94
+
When using `useRef`, you have two options when creating a ref container that does not have an initial value:
95
+
96
+
```ts
97
+
const ref1 =useRef<HTMLElement>(null!);
98
+
const ref2 =useRef<HTMLElement|null>(null);
99
+
```
100
+
101
+
The first option will make `ref1.current` read-only, and is intended to be passed in to built-in `ref` attributes that React will manage (because React handles setting the `current` value for you).
102
+
103
+
<details>
104
+
<summary>What is the <code>!</code> at the end of <code>null!</code>?</summary>
105
+
106
+
`null!` is a non-null assertion operator (the `!`). It asserts that any expression before it is not `null` or `undefined`, so if you have `useRef<HTMLElement>(null!)` it means that you're instantiating the ref with a current value of `null` but lying to TypeScript that it's not `null`.
107
+
108
+
```ts
109
+
function MyComponent() {
110
+
const ref1 =useRef<HTMLElement>(null!);
111
+
useEffect(() => {
112
+
doSomethingWith(ref1.current); // TypeScript won't require null-check e.g. ref1 && ref1.current
113
+
});
114
+
return <divref={ref1}> etc</div>;
115
+
}
116
+
```
117
+
118
+
</details>
119
+
120
+
The second option will make `ref2.current` mutable, and is intended for "instance variables" that you manage yourself.
77
121
78
122
```tsx
79
123
function TextInputWithFocusButton() {
@@ -101,53 +145,25 @@ function TextInputWithFocusButton() {
101
145
102
146
example from [Stefan Baumgartner](https://fettblog.eu/typescript-react/hooks/#useref)
103
147
104
-
**useReducer**
148
+
## useImperativeHandle
105
149
106
-
You can use [Discriminated Unions](https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions) for reducer actions. Don't forget to define the return type of reducer, otherwise TypeScript will infer it.
150
+
_we dont have much here, but this is from [a discussion in our issues](https://.com/typescript-cheatsheets/react/issues/106)_
107
151
108
152
```tsx
109
-
typeAppState= {};
110
-
typeAction=
111
-
| { type:"SET_ONE"; payload:string } // typescript union types allow for leading |'s to have nicer layout
function List<ItemType>(props:ListProps<ItemType>) {
159
+
useImperativeHandle(props.innerRef, () => ({
160
+
scrollToItem() {},
161
+
}));
162
+
returnnull;
129
163
}
130
164
```
131
165
132
-
[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/C4TwDgpgBAgmYGVgENjQLxQN4F8CwAUKJLAMbACWA9gHZTqFRQA+2UxEAXFAEQICiAFQD6AeQBy-HgG4oYZCAA2VZABNuAZ2AAnCjQDmUfASass7cF14CRggOqiZchcrXcaAVwC2AIwjajaUJCCAAPMCptYCgAMw8acmo6bQhVD1J-AAotVCs4RBQ0ABooZETabhhymgBKSvgkXOxGKA0AdwpgUgALKEyyyloAOg4a5pMmKFJkDWg+ITFJHk4WyagU4A9tOixVtaghw5zivbXaKwGkofklFVUoAHoHqAADG9dVF6gKDVadPX0p0Ce2ms2sC3sjhWEzWGy2OyBTEOQ2OECKiPYbSo3Euw3ed0ezzeLjuXx+UE8vn8QJwQRhUFUEBiyA8imA0P26wgm22f1ydKYxhwQA)
133
-
134
-
<details>
135
-
136
-
<summary><b>Usage with `Reducer` from `redux`</b></summary>
137
-
138
-
In case you use the [redux](https://.com/reduxjs/redux) library to write reducer function, It provides a convenient helper of the format `Reducer<State, Action>` which takes care of the return type for you.
If you are returning an array in your Custom Hook, you will want to avoid type inference as TypeScript will infer a union type (when you actually want different types in each position of the array). Instead, use [TS 3.4 const assertions](https://devblogs.microsoft.com/typescript/announcing-typescript-3-4/#const-assertions):
For "true" reusability you should also consider exposing a ref for your HOC. You can use `React.forwardRef<Ref, Props>` as documented in [the basic cheatsheet](https://.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/README.md#forwardrefcreateref), but we are interested in more real world examples. [Here is a nice example in practice](https://gist..com/OliverJAsh/d2f462b03b3e6c24f5588ca7915d010e) from @OliverJAsh.
95
+
For "true" reusability you should also consider exposing a ref for your HOC. You can use `React.forwardRef<Ref, Props>` as documented in [the basic cheatsheet](https://.com/typescript-cheatsheets/react-typescript-cheatsheet/blob/master/README.md#forwardrefcreateref), but we are interested in more real world examples. [Here is a nice example in practice](https://gist..com/OliverJAsh/d2f462b03b3e6c24f5588ca7915d010e) from @OliverJAsh (note - it still has some rough edges, we need help to test this out/document this).
0 commit comments