diff --git a/README.md b/README.md
index 70800d68..f4dd5048 100644
--- a/README.md
+++ b/README.md
@@ -2405,6 +2405,7 @@ It is worth mentioning some resources to help you get started:
- Marius Schultz: https://blog.mariusschulz.com/series/typescript-evolution with an [Egghead.io course](https://egghead.io/courses/advanced-static-types-in-typescript)
- Basarat's Deep Dive: https://basarat.gitbook.io/typescript/
- 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`)
+- Go through [Remo Jansen's TypeScript ladder](http://www.techladder.io/?tech=typescript)
- Shu Uesugi: [TypeScript for Beginner Programmers](https://ts.chibicode.com/)
diff --git a/docs/advanced/patterns_by_usecase.md b/docs/advanced/patterns_by_usecase.md
index 2a2b59b5..6355f9ef 100644
--- a/docs/advanced/patterns_by_usecase.md
+++ b/docs/advanced/patterns_by_usecase.md
@@ -315,6 +315,24 @@ type NumbersChildren = number[];
type TwoNumbersChildren = [number, number];
```
+
+
+Don't forget that you can also use `prop-types` if TS fails you.
+
+
+```ts
+Parent.propTypes = {
+ children: PropTypes.shape({
+ props: PropTypes.shape({
+ // could share `propTypes` to the child
+ value: PropTypes.string.isRequired,
+ }),
+ }).isRequired,
+};
+```
+
+
+
### What You CANNOT Do
The thing you cannot do is **specify which components** the children are, e.g. If you want to express the fact that "React Router `` can only have `` as children, nothing else is allowed" in TypeScript.
diff --git a/docs/basic/getting-started/default-props.md b/docs/basic/getting-started/default-props.md
index f0364890..7bb7c944 100644
--- a/docs/basic/getting-started/default-props.md
+++ b/docs/basic/getting-started/default-props.md
@@ -65,7 +65,7 @@ const Greet = ({ age = 21 }: GreetProps) => {
// class components
// ////////////////
type GreetProps = {
- age: number;
+ age?: number;
};
class Greet extends React.Component {
@@ -125,7 +125,7 @@ export class MyComponent extends React.Component {
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.
-[See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react-typescript-cheatsheet/issues/57).
+[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).
diff --git a/docs/basic/getting-started/hooks.md b/docs/basic/getting-started/hooks.md
index 4fd6986f..04116d58 100644
--- a/docs/basic/getting-started/hooks.md
+++ b/docs/basic/getting-started/hooks.md
@@ -5,7 +5,7 @@ title: Hooks
Hooks are [supported in `@types/react` from v16.8 up](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/a05cc538a42243c632f054e42eab483ebf1560ab/types/react/index.d.ts#L800-L1031).
-**useState**
+## useState
Type inference works very well most of the time:
@@ -24,37 +24,53 @@ const [user, setUser] = React.useState(null);
setUser(newUser);
```
-**useRef**
+## useReducer
-When using `useRef`, you have two options when creating a ref container that does not have an initial value:
+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.
-```ts
-const ref1 = useRef(null!);
-const ref2 = useRef(null);
+```tsx
+type AppState = {};
+type Action =
+ | { type: "SET_ONE"; payload: string } // typescript union types allow for leading |'s to have nicer layout
+ | { type: "SET_TWO"; payload: number };
+
+export function reducer(state: AppState, action: Action): AppState {
+ switch (action.type) {
+ case "SET_ONE":
+ return {
+ ...state,
+ one: action.payload, // `payload` is string
+ };
+ case "SET_TWO":
+ return {
+ ...state,
+ two: action.payload, // `payload` is number
+ };
+ default:
+ return state;
+ }
+}
```
-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).
+[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/C4TwDgpgBAgmYGVgENjQLxQN4F8CwAUKJLAMbACWA9gHZTqFRQA+2UxEAXFAEQICiAFQD6AeQBy-HgG4oYZCAA2VZABNuAZ2AAnCjQDmUfASass7cF14CRggOqiZchcrXcaAVwC2AIwjajaUJCCAAPMCptYCgAMw8acmo6bQhVD1J-AAotVCs4RBQ0ABooZETabhhymgBKSvgkXOxGKA0AdwpgUgALKEyyyloAOg4a5pMmKFJkDWg+ITFJHk4WyagU4A9tOixVtaghw5zivbXaKwGkofklFVUoAHoHqAADG9dVF6gKDVadPX0p0Ce2ms2sC3sjhWEzWGy2OyBTEOQ2OECKiPYbSo3Euw3ed0ezzeLjuXx+UE8vn8QJwQRhUFUEBiyA8imA0P26wgm22f1ydKYxhwQA)
- What is the !
at the end of null!
?
-`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(null!)` it means that you're instantiating the ref with a current value of `null` but lying to TypeScript that it's not `null`.
+Usage with `Reducer` from `redux`
-```ts
-function MyComponent() {
- const ref1 = useRef(null!);
- useEffect(() => {
- doSomethingWith(ref1.current); // TypeScript won't require null-check e.g. ref1 && ref1.current
- });
- return etc
;
-}
+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` which takes care of the return type for you.
+
+So the above reducer example becomes:
+
+```tsx
+import { Reducer } from 'redux';
+
+export function reducer: Reducer() {}
```
-The second option will make `ref2.current` mutable, and is intended for "instance variables" that you manage yourself.
-
-**useEffect**
+## useEffect
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:
@@ -73,7 +89,35 @@ function DelayedEffect(props: { timerMs: number }) {
}
```
-**useRef**
+## useRef
+
+When using `useRef`, you have two options when creating a ref container that does not have an initial value:
+
+```ts
+const ref1 = useRef(null!);
+const ref2 = useRef(null);
+```
+
+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).
+
+
+ What is the !
at the end of null!
?
+
+`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(null!)` it means that you're instantiating the ref with a current value of `null` but lying to TypeScript that it's not `null`.
+
+```ts
+function MyComponent() {
+ const ref1 = useRef(null!);
+ useEffect(() => {
+ doSomethingWith(ref1.current); // TypeScript won't require null-check e.g. ref1 && ref1.current
+ });
+ return etc
;
+}
+```
+
+
+
+The second option will make `ref2.current` mutable, and is intended for "instance variables" that you manage yourself.
```tsx
function TextInputWithFocusButton() {
@@ -101,53 +145,25 @@ function TextInputWithFocusButton() {
example from [Stefan Baumgartner](https://fettblog.eu/typescript-react/hooks/#useref)
-**useReducer**
+## useImperativeHandle
-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.
+_we dont have much here, but this is from [a discussion in our issues](https://github.com/typescript-cheatsheets/react/issues/106)_
```tsx
-type AppState = {};
-type Action =
- | { type: "SET_ONE"; payload: string } // typescript union types allow for leading |'s to have nicer layout
- | { type: "SET_TWO"; payload: number };
-
-export function reducer(state: AppState, action: Action): AppState {
- switch (action.type) {
- case "SET_ONE":
- return {
- ...state,
- one: action.payload, // `payload` is string
- };
- case "SET_TWO":
- return {
- ...state,
- two: action.payload, // `payload` is number
- };
- default:
- return state;
- }
+type ListProps = {
+ items: ItemType[];
+ innerRef?: React.Ref<{ scrollToItem(item: ItemType): void }>;
+};
+
+function List(props: ListProps) {
+ useImperativeHandle(props.innerRef, () => ({
+ scrollToItem() {},
+ }));
+ return null;
}
```
-[View in the TypeScript Playground](https://www.typescriptlang.org/play/?jsx=2#code/C4TwDgpgBAgmYGVgENjQLxQN4F8CwAUKJLAMbACWA9gHZTqFRQA+2UxEAXFAEQICiAFQD6AeQBy-HgG4oYZCAA2VZABNuAZ2AAnCjQDmUfASass7cF14CRggOqiZchcrXcaAVwC2AIwjajaUJCCAAPMCptYCgAMw8acmo6bQhVD1J-AAotVCs4RBQ0ABooZETabhhymgBKSvgkXOxGKA0AdwpgUgALKEyyyloAOg4a5pMmKFJkDWg+ITFJHk4WyagU4A9tOixVtaghw5zivbXaKwGkofklFVUoAHoHqAADG9dVF6gKDVadPX0p0Ce2ms2sC3sjhWEzWGy2OyBTEOQ2OECKiPYbSo3Euw3ed0ezzeLjuXx+UE8vn8QJwQRhUFUEBiyA8imA0P26wgm22f1ydKYxhwQA)
-
-
-
-Usage with `Reducer` from `redux`
-
-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` which takes care of the return type for you.
-
-So the above reducer example becomes:
-
-```tsx
-import { Reducer } from 'redux';
-
-export function reducer: Reducer() {}
-```
-
-
-
-**Custom Hooks**
+## Custom Hooks
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):
diff --git a/docs/hoc/full-example.md b/docs/hoc/full-example.md
index 5a6ae49c..74e64860 100644
--- a/docs/hoc/full-example.md
+++ b/docs/hoc/full-example.md
@@ -92,4 +92,4 @@ export function inject(
### Using `forwardRef`
-For "true" reusability you should also consider exposing a ref for your HOC. You can use `React.forwardRef[` 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.
+For "true" reusability you should also consider exposing a ref for your HOC. You can use `React.forwardRef][` 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).
]