DEV Community

Maksim
Maksim

Posted on • Edited on

Typescript. Simple React components.

Hello there. I very like to use React and Typescript. Almost in each new project need simple components, like atoms, for example: button, input, checkbox etc. I have some best practices to make it friendly for all members of team, but also with strict typings. Let's get a look, maybe it will be helpful for you too.

Button

import React from 'react';

interface IProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  block?: boolean; // Your some custom prop
}

export const Button: React.FunctionComponent<IProps> = ({ block, children, ...shared }) => {
  return <button {...shared}>{children}</button>;
}

Button.defaultProps = {
  type: 'button',
}
Enter fullscreen mode Exit fullscreen mode

That's it. You have custom Button component, that supports all native button attributes with strict typings. You can put common things for all buttons in project, like styles or some business logic.

For use

import React from 'react'

instead of

import * as React from 'react'

add in your tsconfig.json property esModuleInterop: true

Input

import React from 'react';

interface IProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'value'> {
  value: string;

  onChange(value: string): void;
}

export const Input: React.FunctionComponent<IProps> = ({ children, onChange, ...shared }) => {
  return <input onChange={e => onChange(e.target.value)} {...shared} />;
}

Input.defaultProps = {
  type: 'text',
};
Enter fullscreen mode Exit fullscreen mode

The Omit helper type was added in Typescript 3.5. If you use previous version of Typescript, just add this string:

type Omit<T, K> = Pick<T, Exclude<keyof T, K>>

Checkbox

import React from 'react';

interface IProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'> {
  onChange(value: boolean): void;
}

export const Checkbox: React.FunctionComponent<IProps> = ({ children, 
onChange, ...shared }) => {
  return <input onChange={e => onChange(e.target.checked)} {...shared} />
}

Checkbox.defaultProps = {
  type: 'checkbox',  
}
Enter fullscreen mode Exit fullscreen mode

Now you can use it like here:

<Checkbox checked={false} onChange={toggleCheckbox} />
Enter fullscreen mode Exit fullscreen mode

It is end of small tutorial. If it will be helpful for someone, I can continue to explain some good things of React and Typescript. Thanks for attention.

Top comments (11)

Collapse
 
stearm profile image
Stefano Armenes

You can also use React.FC instead of React.FunctionComponent 😃

Collapse
 
pretaporter profile image
Maksim

Thx) Awesome!

Collapse
 
kristemmerman profile image
Kris Temmerman

Nice article! you've made a small typo

export const Button: React.FunctionComonent<IProps> = ({ block, ...shared }) => {
  return <button {...shared}>{children}</button>;
}

should be Component or .FC

Collapse
 
pretaporter profile image
Maksim

React.FC and React.FunctionComponent is the same

Collapse
 
kristemmerman profile image
Kris Temmerman • Edited

Yeah I know but look closely.
thepracticaldev.s3.amazonaws.com/i...

Thread Thread
 
pretaporter profile image
Maksim

Oh, sorry! Thanks)

Collapse
 
charlex profile image
HCB • Edited

Instead of defaultProps, I use:

export const Button: React.FunctionComponent<IProps> = ({ block, children, type = 'button', ...shared }) => {
  return <button type={type} {...shared}>{children}</button>;

}
Collapse
 
mbrtn profile image
Ruslan Shashkov • Edited

It also would be better to use Extract on the shared button props to extract only InputHTMLAttributes<HTMLInputElement> props for <button {...extractedProps}>. In case if you decided to use some custom props for example loading: boolean it will also be sent to <button/> and cause warnings that your loading prop is not in default button props.

Collapse
 
ericandre615 profile image
Eric Andre

I'm a little confused. You keep saying this provides "strict" typing, which I assume you mean strong typing. Since typescript happens before runtime and converts the code to javascript which will be executed in a javascript runtime, which is weakly typed your code will also be weakly typed. Typescript won't magically make the javascript runtime strongly typed. Are you meaning to say it provides static typing? Sorry, this very much is a semantic issue I'm trying to clarify.

Collapse
 
pretaporter profile image
Maksim

I mean, that you have typings better than any and unnecessary to declare each native html property.

Collapse
 
wolverineks profile image
Kevin Sullivan

Although, there are differences between interface extends and &