Extracting Props Types From Components
— React, TypeScript
Introduction
I like tiny components that doing one thing and can be easily reused to build more sophisticated elements. The component file should export just the component and nothing more.
Internal things like interfaces, helper methods should be hidden from the outer world, if they are used also in other places it indicates that there should be moved somewhere else (shared, helpers, interfaces, etc.). Props' definition is strictly related to the component and no-one should import and use it explicitly.
I noticed that people often export components together with props' interface definition. For example to have access to these types in unit tests.
1import React, { FC } from 'react'23export interface ButtonProps {4 text: string5 type?: 'button' | 'submit' | 'reset'6 size?: string7 onClick?: () => {}8}910export const Button: FC<ButtonProps> = ({11 text,12 type = 'button',13 size = 'lg',14 onClick = () => null,15}) => {16 return (17 <button type={type} className={`button-${size}`} onClick={onClick}>18 {text}19 </button>20 )21}
1import React from 'react'2import { render } from '@testing-library/react'34import { Button, ButtonProps } from './Button'56let props: ButtonPrps78beforeEach(() => {9 props = {10 text: 'foo',11 type: 'submit',12 size: 'lg',13 onClick: jest.fn(),14 }15})1617it('renders the button component', () => {18 const { baseElement } = render(<Button {...props} />)19 expect(baseElement).toMatchSnapshot()20})2122/* Other component tests */
Solution
Instead of exporting interfaces and then importing them manually, we can use React.ComponentProps
.
This helper allows extracting props' types from the component in a declarative way.
1import React from 'react'2import { Button } from './Button'34let props: React.ComponentProps<typeof Button>5let type: React.ComponentProps<typeof Button>['type'] = 'reset'
After these changes, we can get rid of unnecessary import and export.
As a result, we have less code that is easier to understand. When someone goes to our component, won't be confused, why somebody decided to export props' interface.