Skip to content

Commit f06bea6

Browse files
fixed Linked article on defaultProps docs is paywalled issue
1 parent 436b5f6 commit f06bea6

File tree

1 file changed

+34
-153
lines changed

1 file changed

+34
-153
lines changed

README.md

Lines changed: 34 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -846,213 +846,94 @@ class Comp extends React.PureComponent<Props, State> {
846846

847847
<!--START-SECTION:default-props-->
848848

849-
#### You May Not Need `defaultProps`
849+
#### You May Not Need `defaultProps` Anymore
850850

851-
As per [this tweet](https://twitter.com/dan_abramov/status/1133878326358171650), defaultProps will eventually be deprecated. You can check the discussions here:
851+
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.
852852

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

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

858-
Function Components:
858+
##### Function Components: Use Default Values
859+
860+
Instead of using `defaultProps`, you can define default values inline for function components:
859861

860862
```tsx
861863
type GreetProps = { age?: number };
862864

863-
const Greet = ({ age = 21 }: GreetProps) => // etc
865+
const Greet = ({ age = 21 }: GreetProps) => {
866+
return <div>{`Hello, I am ${age} years old.`}</div>;
867+
};
864868
```
865869

866-
Class Components:
870+
##### Class Components: `defaultProps` Still Supported
871+
872+
For class components, `defaultProps` is still a valid way to set default values:
867873

868874
```tsx
869875
type GreetProps = {
870876
age?: number;
871877
};
872878

873879
class Greet extends React.Component<GreetProps> {
880+
static defaultProps = {
881+
age: 21,
882+
};
883+
874884
render() {
875-
const { age = 21 } = this.props;
876-
/*...*/
885+
return <div>{`Hello, I am ${this.props.age} years old.`}</div>;
877886
}
878887
}
879888

880889
let el = <Greet age={3} />;
881890
```
882891

883-
#### Typing `defaultProps`
892+
#### Typing `defaultProps` in TypeScript
884893

885-
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).
894+
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.
886895

887-
**Function Components**
896+
##### Function Components
888897

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

895901
const defaultProps = {
896902
age: 21,
897903
};
898904

899905
const Greet = (props: GreetProps) => {
900-
// etc
906+
return <div>{`Hello, I am ${props.age} years old.`}</div>;
901907
};
908+
902909
Greet.defaultProps = defaultProps;
903910
```
904911

905-
_[See this in TS Playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAOKVYwAKxY6ALxwA3igDmWAFxwAdgFcQAIyxQ4AXzgAyOM1YQCcACZYCyeQBte-VPVwRZqeCbOXrEAXGEi6cCdLgAJgBGABo6dXo6e0d4TixuLzgACjAbGXjuPg9UAEovAD5RXzhKGHkoWTgAHiNgADcCkTScgDpkSTgAeiQFZVVELvVqrrrGiPpMmFaXcytsz2FZtwXbOiA)_
906-
907-
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:
912+
##### Class Components
908913

909914
```tsx
910-
type GreetProps = typeof Greet.defaultProps & {
911-
age: number;
912-
};
915+
type GreetProps = typeof Greet.defaultProps & { age: number };
913916

914917
class Greet extends React.Component<GreetProps> {
915918
static defaultProps = {
916919
age: 21,
917920
};
918-
/*...*/
919-
}
920-
921-
// Type-checks! No type assertions needed!
922-
let el = <Greet age={3} />;
923-
```
924-
925-
<details>
926-
<summary><b><code>React.JSX.LibraryManagedAttributes</code> nuance for library authors</b></summary>
927-
928-
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`.
929-
930-
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:
931-
932-
```tsx
933-
// internal contract, should not be exported out
934-
type GreetProps = {
935-
age: number;
936-
};
937-
938-
class Greet extends Component<GreetProps> {
939-
static defaultProps = { age: 21 };
940-
}
941-
942-
// external contract
943-
export type ApparentGreetProps = React.JSX.LibraryManagedAttributes<
944-
typeof Greet,
945-
GreetProps
946-
>;
947-
```
948-
949-
This will work properly, although hovering over`ApparentGreetProps`may be a little intimidating. You can reduce this boilerplate with the`ComponentProps` utility detailed below.
950-
951-
</details>
952-
953-
#### Consuming Props of a Component with defaultProps
954-
955-
A component with `defaultProps` may seem to have some required props that actually aren't.
956-
957-
##### Problem Statement
958-
959-
Here's what you want to do:
960-
961-
```tsx
962-
interface IProps {
963-
name: string;
964-
}
965-
const defaultProps = {
966-
age: 25,
967-
};
968-
const GreetComponent = ({ name, age }: IProps & typeof defaultProps) => (
969-
<div>{`Hello, my name is ${name}, ${age}`}</div>
970-
);
971-
GreetComponent.defaultProps = defaultProps;
972-
973-
const TestComponent = (props: React.ComponentProps<typeof GreetComponent>) => {
974-
return <h1 />;
975-
};
976-
977-
// Property 'age' is missing in type '{ name: string; }' but required in type '{ age: number; }'
978-
const el = <TestComponent name="foo" />;
979-
```
980-
981-
##### Solution
982-
983-
Define a utility that applies `React.JSX.LibraryManagedAttributes`:
984-
985-
```tsx
986-
type ComponentProps<T> = T extends
987-
| React.ComponentType<infer P>
988-
| React.Component<infer P>
989-
? React.JSX.LibraryManagedAttributes<T, P>
990-
: never;
991-
992-
const TestComponent = (props: ComponentProps<typeof GreetComponent>) => {
993-
return <h1 />;
994-
};
995-
996-
// No error
997-
const el = <TestComponent name="foo" />;
998-
```
999-
1000-
[_See this in TS Playground_](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAKjgQwM5wEoFNkGN4BmUEIcARFDvmQNwBQdMAnmFnAMImQB2W3MABWJhUAHgAqAPjgBeOOLhYAHjD4ATdNjwwAdJ3ARe-cSyyjg3AlihwB0gD6Yqu-Tz4xzl67cl04cAH44ACkAZQANHQAZYAAjKGQoJgBZZG5kAHMsNQBBGBgoOIBXVTFxABofPzgALjheADdrejoLVSgCPDYASSEIETgAb2r0kCw61AKLDPoAXzpcQ0m4NSxOooAbQWF0OWH-TPG4ACYAVnK6WfpF7mWAcUosGFdDd1k4AApB+uQxysO4LM6r0dnAAGRwZisCAEFZrZCbbb9VAASlk0g+1VEamADUkgwABgAJLAbDYQSogJg-MZwYDoAAkg1GWFmlSZh1mBNmogA9Di8XQUfQHlgni8jLpVustn0BnJpQjZTsWrzeXANsh2gwbstxFhJhK3nIPmAdnUjfw5WIoVgYXBReKuK9+JI0TJpPs4JQYEUoNw4KIABYARjgvN8VwYargADkIIooMQoAslvBSe8JAbns7JTSsDIyAQIBAyOHJDQgA)
1001-
1002-
#### Misc Discussions and Knowledge
1003-
1004-
<details>
1005-
<summary><b>Why does <code>React.FC</code> break <code>defaultProps</code>?</b></summary>
1006-
1007-
You can check the discussions here:
1008-
1009-
- https://medium.com/@martin_hotell/10-typescript-pro-tips-patterns-with-or-without-react-5799488d6680
1010-
- https://github.com/DefinitelyTyped/DefinitelyTyped/issues/30695
1011-
- https://github.com/typescript-cheatsheets/react/issues/87
1012-
1013-
This is just the current state and may be fixed in future.
1014-
1015-
</details>
1016921

1017-
<details>
1018-
<summary><b>TypeScript 2.9 and earlier</b></summary>
1019-
1020-
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:
1021-
1022-
```ts
1023-
type Props = Required<typeof MyComponent.defaultProps> & {
1024-
/* additional props here */
1025-
};
1026-
1027-
export class MyComponent extends React.Component<Props> {
1028-
static defaultProps = {
1029-
foo: "foo",
1030-
};
922+
render() {
923+
return <div>{`Hello, I am ${this.props.age} years old.`}</div>;
924+
}
1031925
}
1032926
```
1033927

1034-
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!
928+
#### Additional Information
1035929

1036-
```ts
1037-
interface IMyComponentProps {
1038-
firstProp?: string;
1039-
secondProp: IPerson[];
1040-
}
1041-
1042-
export class MyComponent extends React.Component<IMyComponentProps> {
1043-
public static defaultProps: Partial<IMyComponentProps> = {
1044-
firstProp: "default",
1045-
};
1046-
}
1047-
```
1048-
1049-
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.
930+
For more advanced use cases, you can explore the following links:
1050931

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

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

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

1057938
<!--END-SECTION:default-props-->
1058939

0 commit comments

Comments
 (0)