1.0.1 • Published 6 years ago
props-type v1.0.1
props-type

Utility type that defines the type of the React component props through propTypes and defaultProps in TypeScript
Table of contents
Installation
# with NPM
$ npm install --save-dev props-type
# with Yarn
$ yarn add --dev props-typePrerequisite
typescript>= 2.8 (recommend 3.0+ because of support fordefaultPropsin JSX)@types/prop-types>= 15.5.4
Usage
import PropsType from 'props-type';
// Without defaultProps
type Props = PropsType<typeof propTypes>;
// With defaultProps
type Props = PropsType<typeof propTypes, typeof defaultProps>;Type Inference
Optional (without isRequired)
without defaultProps
const propTypes = { disabled: PropTypes.bool };
type Props = PropsType<typeof propTypes>;- Internal :
Propstype isdisabled: boolean | null | undefined - External :
<Button disabled?: boolean | null | undefined />
with defaultProps
const propTypes = { disabled: PropTypes.bool };
const defaultProps = { disabled: false };
type Props = PropsType<typeof propTypes, typeof defaultProps>;- Internal :
Propstype isboolean - External :
<Button disabled?: boolean | undefined />
Required (with isRequired)
without defaultProps
const propTypes = { disabled: PropTypes.bool.isRequired };
type Props = PropsType<typeof propTypes>;- Internal :
Propstype isdisabled: boolean - External :
<Button disabled: boolean />
with defaultProps
const propTypes = { disabled: PropTypes.bool.isRequired };
const defaultProps = { disabled: false };
type Props = PropsType<typeof propTypes, typeof defaultProps>;- Internal :
Propstype isdisabled: boolean - External :
<Button disabled?: boolean | undefined />
Example
without defaultProps
External
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- required :
disabled,onClick - optional :
className,onDoubleClick
Internal
function Button({ className, disabled, onClick, onDoubleClick }: ButtonProps) {
return (
<button
className={className}
disabled={disabled}
onClick={onClick}
onDoubleClick={onDoubleClick}
/>
);
}
Button.propTypes = propTypes;classNametype :string | null | undefineddisabledtype :booleanonClicktype :((...args: any[]) => any)onDoubleClicktype :((...args: any[]) => any) | null | undefined
with defaultProps
External
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'- required :
disabled,onClick - optional :
className,onDoubleClick
Internal
function Button({ className, disabled, onClick, onDoubleClick }: ButtonProps) {
return (
<button
className={className}
disabled={disabled}
onClick={onClick}
onDoubleClick={onDoubleClick}
/>
);
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;classNametype :stringdisabledtype :booleanonClicktype :((...args: any[]) => any)onDoubleClicktype :(event: React.MouseEvent<HTMLButtonElement>) => void
null or undefined in defaultProps
External
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} />- required : N/A
- optional :
className,testId
Internal
function Button({ className, testId }: ButtonProps) {
return <button className={className} data-testid={testId} />;
}
Button.propTypes = propTypes;
Button.defaultProps = defaultProps;classNametype :string | nulltestIdtype :string | undefined
Limits
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 prop-types typescript type declaration currently have problems related to InferProps type (in @types/prop-types). 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';
};Thanks
This package is inspired by Brie Bunge in Adopting TypeScript at Scale, JSConf Hawaii 2019
License
MIT © Taehwan Noh