TypeScript with React Components ?

drlacheheb

drLacheheb

Posted on September 11, 2024

TypeScript with React Components ?

In this post, I'm going to discuss why and how to use TypeScript to type React components.

You'll find how to annotate component props, mark a prop optional, and indicate the return type.

1. Why typing React components?

TypeScript is useful if you're coding middle and bigger size web applications. Annotating variables, objects, and functions creates contracts between different parts of your application.

For example, let's say I am the author of a component that displays a formatted date on the screen.

interface FormatDateProps {
  date: Date
}

function FormatDate({ date }: FormatDateProps): JSX.Element {
  return <div>{date.toLocaleString()}</div>;
}
Enter fullscreen mode Exit fullscreen mode

According to the FormatDateProps interface, the component FormatDate accepts the date prop as an instance of Date. This constraint is crucial because the FormatDate component uses the date.toLocaleString() method, which only works with date instances.

Now, the user of the FormatDate component must satisfy this constraint:

<FormatDate date={new Date()} />
Enter fullscreen mode Exit fullscreen mode

If the user passes a string to date instead:

<FormatDate date="Sep 28 2021" />
Enter fullscreen mode Exit fullscreen mode

TypeScript will show a type error, ensuring you catch this issue during development.

2. Typing props

One of the best benefits React gains from TypeScript is prop typing.

Typing a React component is typically a 2-step process:

A) Define the interface that describes the component props.

B) Annotate the props parameter in the functional component.

For example:

interface MessageProps {
  text: string;
  important: boolean;
}

function Message({ text, important }: MessageProps) {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {text}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now, when rendering Message, props must match the defined types:

<Message text="The form has been submitted!" important={false} />
Enter fullscreen mode Exit fullscreen mode

2.1 Props validation

If you provide incorrect props, TypeScript will show a type error during development:

<Message text="The form has been submitted!" important={0} />
Enter fullscreen mode Exit fullscreen mode

2.2 children prop

The children prop holds the content between the opening and closing tags of a component:

<Component>children</Component>
Enter fullscreen mode Exit fullscreen mode

To type the children prop:

interface MessageProps {
  children: JSX.Element | JSX.Element[];
  important: boolean;
}

function Message({ children, important }: MessageProps) {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

You can now pass children like so:

<Message important={false}>
  <span>The form has been submitted!</span>
</Message>
Enter fullscreen mode Exit fullscreen mode

or with multiple elements:

<Message important={false}>
  <span>The form has been submitted!</span>
  <span>Your request will be processed.</span>
</Message>
Enter fullscreen mode Exit fullscreen mode

Challenge: How would you update the MessageProps interface to also support a string value as a child?

2.3 Optional props

To make a prop optional, use ?:

interface MessageProps {
  children: JSX.Element | JSX.Element[];
  important?: boolean;
}

function Message({ children, important = false }: MessageProps) {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now you can skip the important prop:

<Message>
  <span>The form has been submitted!</span>
</Message>
Enter fullscreen mode Exit fullscreen mode

3. Return type

TypeScript can infer the return type of a React functional component, which is usually JSX.Element:

function Message({ children, important = false }: MessageProps): JSX.Element {
  return (
    <div>
      {important ? 'Important message: ' : 'Regular message: '}
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

If the component may return null, use JSX.Element | null:

function ShowText({ show, text }: { show: boolean, text: string }): JSX.Element | null {
  return show ? <div>{text}</div> : null;
}
Enter fullscreen mode Exit fullscreen mode

3.1 Tip: enforce the return type

It's recommended to explicitly set the return type:

function BrokenComponent(): JSX.Element {
  return
    <div>Hello!</div>; // Error caught!
}
Enter fullscreen mode Exit fullscreen mode



Feel free to comment below if you have any thoughts or questions!

💖 💪 🙅 🚩
drlacheheb
drLacheheb

Posted on September 11, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

TypeScript with React Components ?
typescript TypeScript with React Components ?

September 11, 2024