Ozan Tunca

Senior Software Developer, Music Producer

I’m Ozan, a Senior Software Developer working mainly with JavaScript (read TypeScript). I build scalable, maintainable, performant front-ends and back-ends. I'm also an electronic music enthusiast so don't forget to check out my SoundCloud.

The Right Way to Type Function Components in React with TypeScript

Recently, I had this pull request that triggered a short discussion with my teammates. Someone noticed that I used a different method to write types for the function components I wrote whereas there were other methods used in the codebase.

In this bite-sized React article, I'll show you the right way to do it.

Function components from a type-oriented perspective

Functions in general are programmatic tools that take some input, process it and return some output. Function components essentially work the same way. They take properties and convert them into UI elements. You can see below a super basic function component example from reactjs.org using plain JavaScript.

function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

By rewriting this component with TypeScript we aim to make sure that we

  • use the correct properties with their correct types
  • get a value of the correct type returned from the function

Common (and wrong) way to type function components

A method I see often that is used by developers is to define only the type for the component's props and ignore the return value. It looks like this:

interface WelcomeProps {
name: string;
children: React.ReactNode;
}
function Welcome(props: WelcomeProps) {
return <h1>Hello, {props.name}</h1>;
}

This is all good and well, considering TypeScript is smart enough to implicitly recognize the return type. But it can fail you if your function component returns different values based on some conditions. Not to mention that it causes friction between various function components.

The right way

The right way to define types for function components would be using React's own type definition React.FunctionComponent or React.FC. In that case, we would refactor the above code to the one below:

interface WelcomeProps {
name: string;
}
const Welcome: React.FC<WelcomeProps> = (props) => <h1>Hello, {props.name}</h1>;

This version uses React's own type definition which includes the definition for the return type and also props.children attribute.

Conclusion

Consistency in a codebase is very important. It keeps code changes clean and makes onboarding easier. Try to be consistent in your code conventions and use the standard methods of doing things.

If you're interested in more React tips like this, consider subscribing to my weekly newsletter. I promise to make it worth your while.

Footer Logo