Skip to content

Przemysław Konieczniak - Dev Notes

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.

Button.tsx
1import React, { FC } from 'react'
2
3export interface ButtonProps {
4 text: string
5 type?: 'button' | 'submit' | 'reset'
6 size?: string
7 onClick?: () => {}
8}
9
10export 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}
Button.test.tsx
1import React from 'react'
2import { render } from '@testing-library/react'
3
4import { Button, ButtonProps } from './Button'
5
6let props: ButtonPrps
7
8beforeEach(() => {
9 props = {
10 text: 'foo',
11 type: 'submit',
12 size: 'lg',
13 onClick: jest.fn(),
14 }
15})
16
17it('renders the button component', () => {
18 const { baseElement } = render(<Button {...props} />)
19 expect(baseElement).toMatchSnapshot()
20})
21
22/* 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.

Button.test.tsx
1import React from 'react'
2import { Button } from './Button'
3
4let 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.

Resources

© 2020 by Przemysław Konieczniak - Dev Notes. All rights reserved.