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
* Updated README on 2021-04-02T14:21:23.928Z
* Fix missing parenthesis in troubleshooting types code example (typescript-cheatsheets#399)
Co-authored-by: swyx <[email protected]>
* format
* minor improvements to "adding non-standard attributes" (typescript-cheatsheets#400)
* Added event types and their descriptions (typescript-cheatsheets#402)
* Added form types and their descriptions
I was looking for a complete list of form types and couldn't find any anywhere.
I went through the source code and extracted these with adding some description to them, either using MDN's description or some other website explanation.
* Apply suggestions from code review
Co-authored-by: swyx <[email protected]>
* fix: Remove incorrect usage of "widening" (typescript-cheatsheets#405)
Using an intersection type here is actually narrowing the type, but the intent here seems to be to introduce type assertions, not talk about the difference between wider and narrower types.
* add type assertion for useState thanks @priscilaandreaniclosestypescript-cheatsheets#403
* format
* Fixed typo (typescript-cheatsheets#406)
Fixed an issue where a paragraph described three different options as two.
* Add rollpkg as an option for creating libraries (typescript-cheatsheets#407)
* useLocalStorage Type detection bug (typescript-cheatsheets#409)
in my vs code it detects that the type of soredValue is (T | (value: T | ((val: T) => T)) => void)
but it must be just (T)
so it throws error
with this change it solved.
* Updated README on 2021-04-25T20:13:23.562Z
* Clarify useRef hook usages (typescript-cheatsheets#412)
Co-authored-by: swyx <[email protected]>
* Update index.md
* Update from-flow.md
* docs: throw when ref.current is null (typescript-cheatsheets#413)
* Update types.md
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Denis LE <[email protected]>
Co-authored-by: swyx <[email protected]>
Co-authored-by: Sebastian Silbermann <[email protected]>
Co-authored-by: Lars <[email protected]>
Co-authored-by: Gerrit Birkeland <[email protected]>
Co-authored-by: Christopher Kumm <[email protected]>
Co-authored-by: Rafael Pedicini <[email protected]>
Co-authored-by: Mandy YP <[email protected]>
Co-authored-by: Thien Do <[email protected]>
Co-authored-by: Christina Grannas <[email protected]>
Copy file name to clipboardExpand all lines: docs/basic/getting-started/hooks.md
+59-42
Original file line number
Diff line number
Diff line change
@@ -137,65 +137,82 @@ function DelayedEffect(props: { timerMs: number }) {
137
137
138
138
## useRef
139
139
140
-
When using`useRef`, you have two options when creating a ref container that does not have an initial value:
140
+
In TypeScript,`useRef` returns a reference that is either [read-only](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/abd69803c1b710db58d511f4544ec1b70bc9077c/types/react/v16/index.d.ts#L1025-L1039) or [mutable](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/abd69803c1b710db58d511f4544ec1b70bc9077c/types/react/v16/index.d.ts#L1012-L1023), depends on whether your type argument fully covers the initial value or not. Choose one that suits your use case.
141
141
142
-
```ts
143
-
const ref1 =useRef<HTMLElement>(null!);
144
-
const ref2 =useRef<HTMLElement>(null);
145
-
const ref3 =useRef<HTMLElement|null>(null);
146
-
```
142
+
### Option 1: DOM element ref
147
143
148
-
You can see the difference in [this playground](https://www.typescriptlang.org/play#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwCwAUI7hAHarwCCYYcAvHAAUASn4A+OAG9GjOHAD0CBLLnKGcxHABiwKBzgQwMYGxS4WUACbBWAczgwIcSxFwBXEFlYxkxtgDoVTQBJVmBjZAAbOAA3KLcsOAB3YEjogCNE1jc0-zgAGQBPG3tHOAAVQrAsAGVcKGAjOHTCuDdUErhWNgBabLSUVFQsWBNWA2qoX2hA9VU4AGFKXyx0AFk3H3TIxOwCOAB5dIArLHwgpHcoSm84MGJJmFbgdG74ZcsDVkjC2Y01f7yFQsdjvLAEACM-EwVBg-naWD2AB4ABLlNb5GpgZCsACiO083jEgn6kQAhMJ6HMQfpKJCFpE2IkBNg8HCEci0RisTj8VhCTBiaSKVSVIoAaoLnBQuFgFFYvFEikBpkujkMps4FgAB7VfCdLmY7F4gleOFwAByEHg7U63VYfXVg2Go1MhhG0ygf3mAHVUtF6jgYLtwUdTvguta4Bstjs9mGznCpVcbvB7u7YM90B8vj9vYgLkDqWxaeCAEzQ1n4eHDTnoo2801EknqykyObii5SmpnNifA5GMZmCzWOwOJwudwC3xjKUyiLROKRBLJf3NLJO9KanV64xj0koVifQ08k38s1Sv0DJZBxIx5DbRGhk6J5Nua5mu4PEZPOAvSNgsgnxsHmXZzIgRZyDSYIEAAzJWsI1k+BCovWp58gKcAAD5qmkQqtqKHbyCexoYRecw7IQugcAs76ptCdIQv4KZmoRcjyMRaGkU28A4aSKiUXAwwgpYtEfrcAh0mWzF0ax7bsZx3Lceetx8eqAlYPAMAABa6KJskSXAdKwTJ4kwGxCjyKy-bfK05SrDA8mWVagHAbZeScOY0CjqUE6uOgqDaRAOSfKqOYgb8KiMaZ9GSeCEIMkyMVyUwRHWYc7nSvAgUQEk6AjMQXpReWyWGdFLHeBZHEuTCQEZT8xVwaV8BxZCzUWZQMDvuMghBHASJVnCWhTLYApiH1chIqgxpGeCfCSIxAC+Yj3o+8YvvgSLyNNOLjeBGhTTNdLzVJy3reGMBbTtrB7RoB3XbNBAneCsHLatcbPhdV3GrdB1WYhw3IKNZq-W2DCLYRO7QPAljgsgORcDwVJAA), thanks to [this discussion with @rajivpunjabi](https://github.com/typescript-cheatsheets/react/issues/388).
144
+
**[To access a DOM element](https://reactjs.org/docs/refs-and-the-dom.html):** provide only the element type as argument, and use `null` as initial value. In this case, the returned reference will have a read-only `.current` that is managed by React. TypeScript expects you to give this ref to an element's `ref` prop:
149
145
150
-
The first option will bypass nullchecks on `ref1.current`, 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).
151
-
152
-
<details>
153
-
<summary>What is the <code>!</code> at the end of <code>null!</code>?</summary>
154
-
155
-
`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`.
156
-
157
-
```ts
158
-
function MyComponent() {
159
-
const ref1 =useRef<HTMLDivElement>(null!);
146
+
```tsx
147
+
function Foo() {
148
+
// - If possible, prefer as specific as possible. For example, HTMLDivElement
149
+
// is better than HTMLElement and way better than Element.
150
+
// - Technical-wise, this returns RefObject<HTMLDivElement>
151
+
const divRef =useRef<HTMLDivElement>(null);
152
+
160
153
useEffect(() => {
161
-
doSomethingWith(ref1.current);
162
-
// TypeScript won't require null-check e.g. ref1 && ref1.current
154
+
// Note that ref.current may be null. This is expected, because you may
155
+
// conditionally render the ref-ed element, or you may forgot to assign it
156
+
if (!divRef.current) throwError("divRef is not assigned");
157
+
158
+
// Now divRef.current is sure to be HTMLDivElement
159
+
doSomethingWith(divRef.current);
163
160
});
164
-
return <divref={ref1}> etc</div>;
161
+
162
+
// Give the ref to an element so React can manage it for you
163
+
return <divref={divRef}>etc</div>;
165
164
}
166
165
```
167
166
167
+
If you are sure that `divRef.current` will never be null, it is also possible to use the non-null assertion operator `!`:
168
+
169
+
```
170
+
const divRef = useRef<HTMLDivElement>(null!);
171
+
// Later... No need to check if it is null
172
+
doSomethingWith(divRef.current);
173
+
```
174
+
175
+
Note that you are opting out of type safety here - you will have a runtime error if you forget to assign the ref to an element in the render, or if the ref-ed element is conditionally rendered.
176
+
177
+
<details>
178
+
<summary>
179
+
180
+
Tip: Choosing which `HTMLElement` to use
181
+
182
+
</summary>
183
+
184
+
185
+
Refs demand specificity - it is not enough to just specify any old `HTMLElement`. If you don't know the name of the element type you need, you can check [lib.dom.ts](https://github.com/microsoft/TypeScript/blob/v3.9.5/lib/lib.dom.d.ts#L19224-L19343) or make an intentional type error and let the language service tell you:
The second option will infer a `RefObject` instead of a `MutableRefObject`. This means there will be a type error if you try to assign to `ref2.current`.
171
191
172
-
The third option will make `ref3.current` mutable, and is intended for "instance variables" that you manage yourself.
192
+
### Option 2: Mutable value ref
193
+
194
+
**[To have a mutable value](https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables):** provide the type you want, and make sure the initial value fully belongs to that type:
173
195
174
196
```tsx
175
-
function TextInputWithFocusButton() {
176
-
// initialise with null, but tell TypeScript we are looking for an HTMLInputElement
// strict null checks need us to check if inputEl and current exist.
180
-
// but once current exists, it is of type HTMLInputElement, thus it
181
-
// has the method focus! ✅
182
-
if (inputEl&&inputEl.current) {
183
-
inputEl.current.focus();
184
-
}
185
-
};
186
-
return (
187
-
<>
188
-
{/* in addition, inputEl only can be used with input elements. Yay! */}
189
-
<inputref={inputEl}type="text" />
190
-
<buttononClick={onButtonClick}>Focus the input</button>
191
-
</>
192
-
);
197
+
function Foo() {
198
+
// Technical-wise, this returns MutableRefObject<number | null>
199
+
const intervalRef =useRef<number|null>(null);
200
+
201
+
// You manage the ref yourself (that's why it's called MutableRefObject!)
202
+
useEffect(() => {
203
+
intervalRef.current=setInterval(...);
204
+
return () =>clearInterval(intervalRef.current);
205
+
}, []);
206
+
207
+
// The ref is not passed to any element's "ref" prop
208
+
return <buttononClick={/* clearInterval the ref */}>Cancel timer</button>;
193
209
}
194
210
```
195
211
196
-
[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wFgAoCzAVwDsNgJa4AVJADxgElaxqYA6sBgALAGIQ01AM4AhfjCYAKAJRwA3hThwA9DrjBaw4CgA2waUjgB3YSLi1qp0wBo4AI35wYSZ6wCeYEgAymhQwGDw1lYoRHCmEBAA1oYA5nCY0HAozAASLACyADI8fDAAoqZIIEi0MFpwaEzS8IZllXAAvIjEMAB0MkjImAA8+cWl-JXVtTAAfEqOzioA3A1NtC1wTPIwirQAwuZoSV1wql1zGg3aenAt4RgOTqaNIkgn0g5ISAAmcDJvBA3h9TsBMAZeFNXjl-lIoEQ6nAOBZ+jddPpPPAmGgrPDEfAUS1pG5hAYvhAITBAlZxiUoRUqjU6m5RIDhOi7iIUF9RFYaqIIP9MlJpABCOCAUHJ0eDzm1oXAAGSKyHtUx9fGzNSacjaPWq6Ea6gI2Z9EUyVRrXV6gC+DRtVu0RBgxuYSnRIzm6O06h0ACpIdlfr9jExSQyOkxTP5GjkPFZBv9bKIDYSmbNpH04ABNFD+CV+nR2636kby+BETCddTlyo27w0zr4HycfC6L0lvUjLH7baHY5Jas7BRMI7AE42uYSUXed6pkY6HtMDulnQruCrCg2oA)
212
+
### See also
197
213
198
-
example from [Stefan Baumgartner](https://fettblog.eu/typescript-react/hooks/#useref)
214
+
- [Related issue by @rajivpunjabi](https://github.com/typescript-cheatsheets/react/issues/388) - [Playground](https://www.typescriptlang.org/play#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwCwAUI7hAHarwCCYYcAvHAAUASn4A+OAG9GjOHAD0CBLLnKGcxHABiwKBzgQwMYGxS4WUACbBWAczgwIcSxFwBXEFlYxkxtgDoVTQBJVmBjZAAbOAA3KLcsOAB3YEjogCNE1jc0-zgAGQBPG3tHOAAVQrAsAGVcKGAjOHTCuDdUErhWNgBabLSUVFQsWBNWA2qoX2hA9VU4AGFKXyx0AFk3H3TIxOwCOAB5dIArLHwgpHcoSm84MGJJmFbgdG74ZcsDVkjC2Y01f7yFQsdjvLAEACM-EwVBg-naWD2AB4ABLlNb5GpgZCsACiO083jEgn6kQAhMJ6HMQfpKJCFpE2IkBNg8HCEci0RisTj8VhCTBiaSKVSVIoAaoLnBQuFgFFYvFEikBpkujkMps4FgAB7VfCdLmY7F4gleOFwAByEHg7U63VYfXVg2Go1MhhG0ygf3mAHVUtF6jgYLtwUdTvguta4Bstjs9mGznCpVcbvB7u7YM90B8vj9vYgLkDqWxaeCAEzQ1n4eHDTnoo2801EknqykyObii5SmpnNifA5GMZmCzWOwOJwudwC3xjKUyiLROKRBLJf3NLJO9KanV64xj0koVifQ08k38s1Sv0DJZBxIx5DbRGhk6J5Nua5mu4PEZPOAvSNgsgnxsHmXZzIgRZyDSYIEAAzJWsI1k+BCovWp58gKcAAD5qmkQqtqKHbyCexoYRecw7IQugcAs76ptCdIQv4KZmoRcjyMRaGkU28A4aSKiUXAwwgpYtEfrcAh0mWzF0ax7bsZx3Lceetx8eqAlYPAMAABa6KJskSXAdKwTJ4kwGxCjyKy-bfK05SrDA8mWVagHAbZeScOY0CjqUE6uOgqDaRAOSfKqOYgb8KiMaZ9GSeCEIMkyMVyUwRHWYc7nSvAgUQEk6AjMQXpReWyWGdFLHeBZHEuTCQEZT8xVwaV8BxZCzUWZQMDvuMghBHASJVnCWhTLYApiH1chIqgxpGeCfCSIxAC+Yj3o+8YvvgSLyNNOLjeBGhTTNdLzVJy3reGMBbTtrB7RoB3XbNBAneCsHLatcbPhdV3GrdB1WYhw3IKNZq-W2DCLYRO7QPAljgsgORcDwVJAA)
215
+
-[Example from Stefan Baumgartner](https://fettblog.eu/typescript-react/hooks/#useref) - [Playground](https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wFgAoCzAVwDsNgJa4AVJADxgElaxqYA6sBgALAGIQ01AM4AhfjCYAKAJRwA3hThwA9DrjBaw4CgA2waUjgB3YSLi1qp0wBo4AI35wYSZ6wCeYEgAymhQwGDw1lYoRHCmEBAA1oYA5nCY0HAozAASLACyADI8fDAAoqZIIEi0MFpwaEzS8IZllXAAvIjEMAB0MkjImAA8+cWl-JXVtTAAfEqOzioA3A1NtC1wTPIwirQAwuZoSV1wql1zGg3aenAt4RgOTqaNIkgn0g5ISAAmcDJvBA3h9TsBMAZeFNXjl-lIoEQ6nAOBZ+jddPpPPAmGgrPDEfAUS1pG5hAYvhAITBAlZxiUoRUqjU6m5RIDhOi7iIUF9RFYaqIIP9MlJpABCOCAUHJ0eDzm1oXAAGSKyHtUx9fGzNSacjaPWq6Ea6gI2Z9EUyVRrXV6gC+DRtVu0RBgxuYSnRIzm6O06h0ACpIdlfr9jExSQyOkxTP5GjkPFZBv9bKIDYSmbNpH04ABNFD+CV+nR2636kby+BETCddTlyo27w0zr4HycfC6L0lvUjLH7baHY5Jas7BRMI7AE42uYSUXed6pkY6HtMDulnQruCrCg2oA)
For more information on creating type definitions for class components, you can refer to this [post](https://templecoding.com/blog/2016/03/31/creating-typescript-typings-for-existing-react-components) for reference.
546
+
547
+
548
+
## Frequent Known Problems with TypeScript
549
+
550
+
Just a list of stuff that React developers frequently run into, that TS has no solution for. Not necessarily TSX only.
551
+
552
+
### TypeScript doesn't narrow after an object element null check
Copy file name to clipboardExpand all lines: docs/migration/from-flow.md
+1
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,7 @@ title: From Flow
4
4
---
5
5
6
6
- Try flow2ts: `npx flow2ts` - doesn't work 100% but saves some time ([see this and other tips from @braposo](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/pull/79#issuecomment-458227322) at TravelRepublic)
-[Adopting TypeScript at Scale - AirBnB's conversion story and strategy](https://www.youtube.com/watch?v=P-J9Eg7hJwE)
92
+
- Airtable's [Big Bang Migration from Flow to TS](https://medium.com/airtable-eng/the-continual-evolution-of-airtables-codebase-migrating-a-million-lines-of-code-to-typescript-612c008baf5c)
0 commit comments