Utility type that defines the type of the React component props through propTypes and defaultProps in TypeScript
MIT License
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 (Korean)
Table of contents
# with NPM
$ npm install props-type
# with Yarn
$ yarn add props-type
typescript
>= 2.8 (recommend 3.0+ because of support for defaultProps
in JSX)@types/prop-types
>= 15.5.4import PropsType from 'props-type';
// Without defaultProps
type Props = PropsType<typeof propTypes>;
// With defaultProps
type Props = PropsType<typeof propTypes, typeof defaultProps>;
isRequired
)defaultProps
const propTypes = { disabled: PropTypes.bool };
type Props = PropsType<typeof propTypes>;
Props
type is disabled: boolean | null | undefined
<Button disabled?: boolean | null | undefined />
defaultProps
const propTypes = { disabled: PropTypes.bool };
const defaultProps = { disabled: false };
type Props = PropsType<typeof propTypes, typeof defaultProps>;
Props
type is boolean
<Button disabled?: boolean | undefined />
isRequired
)defaultProps
const propTypes = { disabled: PropTypes.bool.isRequired };
type Props = PropsType<typeof propTypes>;
Props
type is disabled: boolean
<Button disabled: boolean />
defaultProps
const propTypes = { disabled: PropTypes.bool.isRequired };
const defaultProps = { disabled: false };
type Props = PropsType<typeof propTypes, typeof defaultProps>;
Props
type is disabled: boolean
<Button disabled?: boolean | undefined />
defaultProps
const propTypes = {
className: PropTypes.string,
disabled: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
onDoubleClick: PropTypes.func,
};
type ButtonProps = PropsType<typeof propTypes>;
// Correct
<Button disabled onClick={onClick} />
<Button className="primary" disabled onClick={onClick} />
<Button disabled onClick={onClick} onDoubleClick={onDoubleClick} />
<Button className="primary" disabled onClick={onClick} onDoubleClick={onDoubleClick} />
// Invalid
<Button /> // Property 'disabled' and 'onClick' is missing
<Button disabled /> // Property 'onClick' is missing
<Button onClick /> // Property 'disabled' is missing
disabled
, onClick
className
, onDoubleClick
function Button({ className, disabled, onClick, onDoubleClick }: ButtonProps) {
return (
<button
className={className}
disabled={disabled}
onClick={onClick}
onDoubleClick={onDoubleClick}
/>
);
}
Button.propTypes = propTypes;
className
type : string | null | undefined
disabled
type : boolean
onClick
type : ((...args: any[]) => any)
onDoubleClick
type : ((...args: any[]) => any) | null | undefined
defaultProps
const propTypes = {
className: PropTypes.string,
disabled: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
onDoubleClick: PropTypes.func,
};
const defaultProps = {
className: 'primary',
onDoubleClick(event: React.MouseEvent<HTMLButtonElement>) {},
};
type ButtonProps = PropsType<typeof propTypes>;
// Correct
<Button disabled onClick={onClick} />
<Button className="secondary" disabled onClick={onClick} />
<Button disabled onClick={onClick} onDoubleClick={(event: React.MouseEvent<HTMLButtonElement>) => {}} />
<Button className="secondary" disabled onClick={onClick} onDoubleClick={(event: React.MouseEvent<HTMLButtonElement>) => {}} />
// Invalid
<Button /> // Property 'disabled' and 'onClick' is missing
<Button disabled /> // Property 'onClick' is missing
<Button onClick={onClick} /> // Property 'disabled' is missing
<Button disabled onClick={onClick} onDoubleClick={(a: number) => {}} /> // Type '(a: number) => void' is not assignable to type '(event: MouseEvent<HTMLButtonElement, MouseEvent>) => void'
disabled
, onClick
className
, onDoubleClick
function Button({ className, disabled, onClick, onDoubleClick }: ButtonProps) {
return (
<button
className={className}
disabled={disabled}
onClick={onClick}
onDoubleClick={onDoubleClick}
/>
);
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
className
type : string
disabled
type : boolean
onClick
type : ((...args: any[]) => any)
onDoubleClick
type : (event: React.MouseEvent<HTMLButtonElement>) => void
null
or undefined
in defaultProps
const propTypes = {
className: PropTypes.string,
testId: PropTypes.string,
};
const defaultProps = {
className: null,
testId: undefined,
};
type ButtonProps = PropsType<typeof propTypes, typeof defaultProps>;
// Correct
<Button />
<Button className={null} />
<Button testId={undefined} />
// Incorrect
<Button className={undefined} />
<Button testId={null} />
className
, testId
function Button({ className, testId }: ButtonProps) {
return <button className={className} data-testid={testId} />;
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
className
type : string | null
testId
type : string | undefined
The prop type of oneOf
in prop-types
is not inferenced to union type.
const propTypes = {
type: PropTypes.oneOf(['button', 'submit', 'reset']),
};
const defaultProps = {
type: 'button',
};
type ButtonProps = PropsType<typeof propTypes, typeof defaultProps>;
function Button({ type }: ButtonProps) {
return <button type={type}>Button</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.
type ButtonProps = PropsType<typeof propTypes, typeof defaultProps> & {
type: 'button' | 'submit' | 'reset';
};
If you use TypeScript 3.4+, it can be solved by using const
assertion.
const propTypes = {
type: PropTypes.oneOf(['button', 'submit', 'reset'] as const),
};
const defaultProps = {
type: 'button' as const,
};
type ButtonProps = PropsType<typeof propTypes, typeof defaultProps>;
This package is inspired by Brie Bunge in Adopting TypeScript at Scale, JSConf Hawaii 2019
MIT © Taehwan Noh