https://github.com/taehwanno/props-type
Utility type that defines the type of the React component props through propTypes and defaultProps in TypeScript
https://github.com/taehwanno/props-type
prop-types react typescript
Last synced: 10 months ago
JSON representation
Utility type that defines the type of the React component props through propTypes and defaultProps in TypeScript
- Host: GitHub
- URL: https://github.com/taehwanno/props-type
- Owner: taehwanno
- License: mit
- Created: 2019-10-09T13:11:13.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2022-12-04T15:36:42.000Z (about 3 years ago)
- Last Synced: 2024-10-13T02:21:01.505Z (about 1 year ago)
- Topics: prop-types, react, typescript
- Language: TypeScript
- Homepage: http://npm.im/props-type
- Size: 159 KB
- Stars: 5
- Watchers: 3
- Forks: 0
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# props-type [](https://badge.fury.io/js/props-type) 
Utility type that defines the type of the React component props through `propTypes` and `defaultProps` in TypeScript.
If you want to know about story of creating this package, see [the blog post](https://medium.com/@taehwanno.dev/react-component-props-typing-with-proptypes-and-defaultprops-in-typescript-233eadb86314) (Korean)
**Table of contents**
- [Installation](#installation)
- [Prerequisite](#prerequisite)
- [Usage](#usage)
- [Type Inference](#type-inference)
- [Example](#example)
- [without `defaultProps`](#without-defaultprops)
- [with `defaultProps`](#with-defaultprops)
- [`null` or `undefined` in `defaultProps`](#null-or-undefined-in-defaultprops)
- [Limits](#limits)
## Installation
```shell
# with NPM
$ npm install props-type
# with Yarn
$ yarn add props-type
```
## Prerequisite
- `typescript` >= 2.8 (recommend 3.0+ because of [support for `defaultProps` in JSX](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#support-for-defaultprops-in-jsx))
- `@types/prop-types` >= 15.5.4
## Usage
```tsx
import PropsType from 'props-type';
// Without defaultProps
type Props = PropsType;
// With defaultProps
type Props = PropsType;
```
## Type Inference
### Optional (without `isRequired`)
#### without `defaultProps`
```tsx
const propTypes = { disabled: PropTypes.bool };
type Props = PropsType;
```
- Internal : `Props` type is `disabled: boolean | null | undefined`
- External : ``
#### with `defaultProps`
```tsx
const propTypes = { disabled: PropTypes.bool };
const defaultProps = { disabled: false };
type Props = PropsType;
```
- Internal : `Props` type is `boolean`
- External : ``
### Required (with `isRequired`)
#### without `defaultProps`
```tsx
const propTypes = { disabled: PropTypes.bool.isRequired };
type Props = PropsType;
```
- Internal : `Props` type is `disabled: boolean`
- External : ``
#### with `defaultProps`
```tsx
const propTypes = { disabled: PropTypes.bool.isRequired };
const defaultProps = { disabled: false };
type Props = PropsType;
```
- Internal : `Props` type is `disabled: boolean`
- External : ``
## Example
### without `defaultProps`
#### External
```tsx
const propTypes = {
className: PropTypes.string,
disabled: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
onDoubleClick: PropTypes.func,
};
type ButtonProps = PropsType;
```
```tsx
// Correct
// Invalid
// Property 'disabled' and 'onClick' is missing
// Property 'onClick' is missing
// Property 'disabled' is missing
```
- required : `disabled`, `onClick`
- optional : `className`, `onDoubleClick`
#### Internal
```tsx
function Button({ className, disabled, onClick, onDoubleClick }: ButtonProps) {
return (
);
}
Button.propTypes = propTypes;
```
- `className` type : `string | null | undefined`
- `disabled` type : `boolean`
- `onClick` type : `((...args: any[]) => any)`
- `onDoubleClick` type : `((...args: any[]) => any) | null | undefined`
### with `defaultProps`
#### External
```tsx
const propTypes = {
className: PropTypes.string,
disabled: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
onDoubleClick: PropTypes.func,
};
const defaultProps = {
className: 'primary',
onDoubleClick(event: React.MouseEvent) {},
};
type ButtonProps = PropsType;
```
```tsx
// Correct
) => {}} />
) => {}} />
// Invalid
// Property 'disabled' and 'onClick' is missing
// Property 'onClick' is missing
// Property 'disabled' is missing
{}} /> // Type '(a: number) => void' is not assignable to type '(event: MouseEvent) => void'
```
- required : `disabled`, `onClick`
- optional : `className`, `onDoubleClick`
#### Internal
```tsx
function Button({ className, disabled, onClick, onDoubleClick }: ButtonProps) {
return (
);
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
```
- `className` type : `string`
- `disabled` type : `boolean`
- `onClick` type : `((...args: any[]) => any)`
- `onDoubleClick` type : `(event: React.MouseEvent) => void`
### `null` or `undefined` in `defaultProps`
#### External
```tsx
const propTypes = {
className: PropTypes.string,
testId: PropTypes.string,
};
const defaultProps = {
className: null,
testId: undefined,
};
type ButtonProps = PropsType;
```
```tsx
// Correct
// Incorrect
```
- required : N/A
- optional : `className`, `testId`
#### Internal
```tsx
function Button({ className, testId }: ButtonProps) {
return ;
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
```
- `className` type : `string | null`
- `testId` type : `string | undefined`
## Limits
The prop type of `oneOf` in `prop-types` is not inferenced to union type.
```tsx
const propTypes = {
type: PropTypes.oneOf(['button', 'submit', 'reset']),
};
const defaultProps = {
type: 'button',
};
type ButtonProps = PropsType;
function Button({ type }: ButtonProps) {
return Button; // Type 'string | null | undefined' is not assignable to type '"button" | "submit" | "reset" | undefined'.
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
```
`type` prop is inferenced to `string` (not a `'button' | 'submit' | 'reset'` union type) because array literal in TypeScript are widen to specific type. If you want to inference `oneOf` as union type, this workaround can help you.
```tsx
type ButtonProps = PropsType & {
type: 'button' | 'submit' | 'reset';
};
```
If you use TypeScript 3.4+, it can be solved by using [`const` assertion](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions).
```tsx
const propTypes = {
type: PropTypes.oneOf(['button', 'submit', 'reset'] as const),
};
const defaultProps = {
type: 'button' as const,
};
type ButtonProps = PropsType;
```
## Thanks
This package is inspired by [Brie Bunge](https://github.com/brieb) in [Adopting TypeScript at Scale, JSConf Hawaii 2019](https://www.youtube.com/watch?v=P-J9Eg7hJwE&feature=youtu.be&t=1063)
## License
MIT © [Taehwan Noh](https://github.com/taehwanno)