Skip to content

Commit 5555f89

Browse files
fixed Linked article on defaultProps docs is paywalled issue
1 parent 828ac1f commit 5555f89

File tree

2 files changed

+196
-322
lines changed

2 files changed

+196
-322
lines changed

docs/basic/getting-started/default-props.md

Lines changed: 34 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -3,210 +3,91 @@ id: default_props
33
title: Typing defaultProps
44
---
55

6-
## You May Not Need `defaultProps`
6+
## You May Not Need `defaultProps` Anymore
77

8-
As per [this tweet](https://twitter.com/dan_abramov/status/1133878326358171650), defaultProps will eventually be deprecated. You can check the discussions here:
8+
According to [Dan Abramov's tweet](https://twitter.com/dan_abramov/status/1133878326358171650), `defaultProps` is on the path to deprecation for function components. Instead, it is recommended to use default values directly in the function component signature for simplicity.
99

10-
- [Original tweet](https://twitter.com/hswolff/status/1133759319571345408)
11-
- More info can also be found in [this article](https://medium.com/@matanbobi/react-defaultprops-is-dying-whos-the-contender-443c19d9e7f1)
10+
For more discussion, check:
1211

13-
The consensus is to use object default values.
12+
- [Original tweet thread](https://twitter.com/hswolff/status/1133759319571345408)
13+
- [Detailed article](https://medium.com/@matanbobi/react-defaultprops-is-dying-whos-the-contender-443c19d9e7f1)
1414

15-
Function Components:
15+
### Function Components: Use Default Values
16+
17+
Instead of using `defaultProps`, you can define default values inline for function components:
1618

1719
```tsx
1820
type GreetProps = { age?: number };
1921

20-
const Greet = ({ age = 21 }: GreetProps) => // etc
22+
const Greet = ({ age = 21 }: GreetProps) => {
23+
return <div>{`Hello, I am ${age} years old.`}</div>;
24+
};
2125
```
2226

23-
Class Components:
27+
### Class Components: `defaultProps` Still Supported
28+
29+
For class components, `defaultProps` is still a valid way to set default values:
2430

2531
```tsx
2632
type GreetProps = {
2733
age?: number;
2834
};
2935

3036
class Greet extends React.Component<GreetProps> {
37+
static defaultProps = {
38+
age: 21,
39+
};
40+
3141
render() {
32-
const { age = 21 } = this.props;
33-
/*...*/
42+
return <div>{`Hello, I am ${this.props.age} years old.`}</div>;
3443
}
3544
}
3645

3746
let el = <Greet age={3} />;
3847
```
3948

40-
## Typing `defaultProps`
49+
## Typing `defaultProps` in TypeScript
4150

42-
Type inference improved greatly for `defaultProps` in [TypeScript 3.0+](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html), although [some edge cases are still problematic](https://github.com/typescript-cheatsheets/react/issues/61).
51+
For TypeScript 3.0 and later, type inference for `defaultProps` has improved. Below is how you can properly type `defaultProps` for both function and class components.
4352

44-
**Function Components**
53+
### Function Components
4554

4655
```tsx
47-
// using typeof as a shortcut; note that it hoists!
48-
// you can also declare the type of DefaultProps if you choose
49-
// e.g. https://github.com/typescript-cheatsheets/react/issues/415#issuecomment-841223219
5056
type GreetProps = { age: number } & typeof defaultProps;
5157

5258
const defaultProps = {
5359
age: 21,
5460
};
5561

5662
const Greet = (props: GreetProps) => {
57-
// etc
63+
return <div>{`Hello, I am ${props.age} years old.`}</div>;
5864
};
65+
5966
Greet.defaultProps = defaultProps;
6067
```
6168

62-
_[See this in TS Playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAOKVYwAKxY6ALxwA3igDmWAFxwAdgFcQAIyxQ4AXzgAyOM1YQCcACZYCyeQBte-VPVwRZqeCbOXrEAXGEi6cCdLgAJgBGABo6dXo6e0d4TixuLzgACjAbGXjuPg9UAEovAD5RXzhKGHkoWTgAHiNgADcCkTScgDpkSTgAeiQFZVVELvVqrrrGiPpMmFaXcytsz2FZtwXbOiA)_
63-
64-
For **Class components**, there are [a couple ways to do it](https://github.com/typescript-cheatsheets/react/pull/103#issuecomment-481061483) (including using the `Pick` utility type) but the recommendation is to "reverse" the props definition:
69+
### Class Components
6570

6671
```tsx
67-
type GreetProps = typeof Greet.defaultProps & {
68-
age: number;
69-
};
72+
type GreetProps = typeof Greet.defaultProps & { age: number };
7073

7174
class Greet extends React.Component<GreetProps> {
7275
static defaultProps = {
7376
age: 21,
7477
};
75-
/*...*/
76-
}
77-
78-
// Type-checks! No type assertions needed!
79-
let el = <Greet age={3} />;
80-
```
8178

82-
<details>
83-
<summary><b><code>React.JSX.LibraryManagedAttributes</code> nuance for library authors</b></summary>
84-
85-
The above implementations work fine for App creators, but sometimes you want to be able to export `GreetProps` so that others can consume it. The problem here is that the way `GreetProps` is defined, `age` is a required prop when it isn't because of `defaultProps`.
86-
87-
The insight to have here is that [`GreetProps` is the _internal_ contract for your component, not the _external_, consumer facing contract](https://github.com/typescript-cheatsheets/react/issues/66#issuecomment-453878710). You could create a separate type specifically for export, or you could make use of the `React.JSX.LibraryManagedAttributes` utility:
88-
89-
```tsx
90-
// internal contract, should not be exported out
91-
type GreetProps = {
92-
age: number;
93-
};
94-
95-
class Greet extends Component<GreetProps> {
96-
static defaultProps = { age: 21 };
97-
}
98-
99-
// external contract
100-
export type ApparentGreetProps = React.JSX.LibraryManagedAttributes<
101-
typeof Greet,
102-
GreetProps
103-
>;
104-
```
105-
106-
This will work properly, although hovering over`ApparentGreetProps`may be a little intimidating. You can reduce this boilerplate with the`ComponentProps` utility detailed below.
107-
108-
</details>
109-
110-
## Consuming Props of a Component with defaultProps
111-
112-
A component with `defaultProps` may seem to have some required props that actually aren't.
113-
114-
### Problem Statement
115-
116-
Here's what you want to do:
117-
118-
```tsx
119-
interface IProps {
120-
name: string;
121-
}
122-
const defaultProps = {
123-
age: 25,
124-
};
125-
const GreetComponent = ({ name, age }: IProps & typeof defaultProps) => (
126-
<div>{`Hello, my name is ${name}, ${age}`}</div>
127-
);
128-
GreetComponent.defaultProps = defaultProps;
129-
130-
const TestComponent = (props: React.ComponentProps<typeof GreetComponent>) => {
131-
return <h1 />;
132-
};
133-
134-
// Property 'age' is missing in type '{ name: string; }' but required in type '{ age: number; }'
135-
const el = <TestComponent name="foo" />;
136-
```
137-
138-
### Solution
139-
140-
Define a utility that applies `React.JSX.LibraryManagedAttributes`:
141-
142-
```tsx
143-
type ComponentProps<T> = T extends
144-
| React.ComponentType<infer P>
145-
| React.Component<infer P>
146-
? React.JSX.LibraryManagedAttributes<T, P>
147-
: never;
148-
149-
const TestComponent = (props: ComponentProps<typeof GreetComponent>) => {
150-
return <h1 />;
151-
};
152-
153-
// No error
154-
const el = <TestComponent name="foo" />;
155-
```
156-
157-
[_See this in TS Playground_](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAMImQB2W3MABWJhUAHgAqAPjgBeOOLhYAHjD4ATdNjwwAdJ3ARe-cSyyjg3AlihwB0gD6Yqu-Tz4xzl67cl04cAH44ACkAZQANHQAZYAAjKGQoJgBZZG5kAHMsNQBBGBgoOIBXVTFxABofPzgALjheADdrejoLVSgCPDYASSEIETgAb2r0kCw61AKLDPoAXzpcQ0m4NSxOooAbQWF0OWH-TPG4ACYAVnK6WfpF7mWAcUosGFdDd1k4AApB+uQxysO4LM6r0dnAAGRwZisCAEFZrZCbbb9VAASlk0g+1VEamADUkgwABgAJLAbDYQSogJg-MZwYDoAAkg1GWFmlSZh1mBNmogA9Di8XQUfQHlgni8jLpVustn0BnJpQjZTsWrzeXANsh2gwbstxFhJhK3nIPmAdnUjfw5WIoVgYXBReKuK9+JI0TJpPs4JQYEUoNw4KIABYARjgvN8VwYargADkIIooMQoAslvBSe8JAbns7JTSsDIyAQIBAyOHJDQgA)
158-
159-
## Misc Discussions and Knowledge
160-
161-
<details>
162-
<summary><b>Why does <code>React.FC</code> break <code>defaultProps</code>?</b></summary>
163-
164-
You can check the discussions here:
165-
166-
- https://medium.com/@martin_hotell/10-typescript-pro-tips-patterns-with-or-without-react-5799488d6680
167-
- https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30695
168-
- https://github.com/typescript-cheatsheets/react/issues/87
169-
170-
This is just the current state and may be fixed in future.
171-
172-
</details>
173-
174-
<details>
175-
<summary><b>TypeScript 2.9 and earlier</b></summary>
176-
177-
For TypeScript 2.9 and earlier, there's more than one way to do it, but this is the best advice we've yet seen:
178-
179-
```ts
180-
type Props = Required<typeof MyComponent.defaultProps> & {
181-
/* additional props here */
182-
};
183-
184-
export class MyComponent extends React.Component<Props> {
185-
static defaultProps = {
186-
foo: "foo",
187-
};
79+
render() {
80+
return <div>{`Hello, I am ${this.props.age} years old.`}</div>;
81+
}
18882
}
18983
```
19084

191-
Our former recommendation used the `Partial type` feature in TypeScript, which means that the current interface will fulfill a partial version on the wrapped interface. In that way we can extend defaultProps without any changes in the types!
192-
193-
```ts
194-
interface IMyComponentProps {
195-
firstProp?: string;
196-
secondProp: IPerson[];
197-
}
198-
199-
export class MyComponent extends React.Component<IMyComponentProps> {
200-
public static defaultProps: Partial<IMyComponentProps> = {
201-
firstProp: "default",
202-
};
203-
}
204-
```
85+
## Additional Information
20586

206-
The problem with this approach is it causes complex issues with the type inference working with `React.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.
87+
For more advanced use cases, you can explore the following links:
20788

208-
[See commentary by @ferdaber here](https://github.com/typescript-cheatsheets/react/issues/57) and [here](https://github.com/typescript-cheatsheets/react/issues/61).
89+
- [TypeScript 3.0 defaultProps improvements](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html)
20990

210-
</details>
91+
[_See this example in TS Playground_](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAOKVYwAKxY6ALxwA3igDmWAFxwAdgFcQAIyxQ4AXzgAyOM1YQCcACZYCyeQBte-VPVwRZqeCbOXrEAXGEi6cCdLgAJgBGABo6dXo6e0d4TixuLzgACjAbGXjuPg9UAEovAD5RXzhKGHkoWTgAHiNgADcCkTScgDpkSTgAeiQFZVVELvVqrrrGiPpMmFaXcytsz2FZtwXbOiA).
21192

212-
[Something to add? File an issue](https://github.com/typescript-cheatsheets/react/issues/new).
93+
---

0 commit comments

Comments
 (0)