You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+1
Original file line number
Diff line number
Diff line change
@@ -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/)
Copy file name to clipboardExpand all lines: docs/advanced/patterns_by_usecase.md
+18
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://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/57).
128
+
[See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/57) and [here](https://github.com/typescript-cheatsheets/react/issues/61).
Copy file name to clipboardExpand all lines: docs/basic/getting-started/hooks.md
+78-62
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://github.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://github.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://github.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://github.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://github.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.github.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://github.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.github.com/OliverJAsh/d2f462b03b3e6c24f5588ca7915d010e) from @OliverJAsh (note - it still has some rough edges, we need help to test this out/document this).
0 commit comments