117

What is the correct way to describe the type of a react component in TypeScript? Say we have a function which returns a react component. The function:

const getTabContent: () => ReactElement = () => {
  switch (tab) {
    case 1:
      return <Images images={images} onSelect={onSelect}/>;
    default:
      return <Search onSelect={onSelect}/>;
  }
};

Here I describe the returning type as ReactElement, but I'm wondering whether it's correct or I should describe it as ReactComponentElement or even somehow completely differently? Also those both types are generics and how to fully describe them if one of them is correct?

UPD ReactElement seems to fit here, because, for example, FC (FunctionComponent) returns it

3
  • React.Component? Commented Jul 9, 2019 at 7:49
  • Thank you @MoshFeu but it doesn't fit. Compiler gets confused Commented Jul 9, 2019 at 8:00
  • "Say we have a function which returns a react component...": Your function does not return a React component, but a React element. See difference-between-react-component-and-react-element Commented Apr 3, 2023 at 13:38

7 Answers 7

101

The correct type for a functional component is React.FunctionComponent or React.FC which is a shortcut alias for it

import React, { FC } from 'react';

const getTabContent: FC = () => {
  switch (tab) {
    case 1:
      return <Images images={images} onSelect={onSelect}/>;
    default:
      return <Search onSelect={onSelect}/>;
  }
};

The FC type simply add the children property to the props argument of the functional component so you can access it:

const SomeComponent: FC = ({ children }) => (
  <div className="hello">{children}</div>
);

FC is a generic type so you can "add" props to your component:

interface SomeComponentProps {
  foo: string;
}

const SomeComponent: FC<SomeComponentProps> = ({ children, foo }) => (
  <div className={`Hello ${foo}`}>{children}</div>
);

Edit: React 18 update

Since React 18, FC doesn't add the children prop implicitly and offers an explicit way to do so with the PropsWithChildren generix type

Example:

type SomeComponentProps = { a: string };

const SomeComponent: FC<SomeComponentProps> = ({ a }) => <div>{a}</div>;

// This will fail when using the following expression
<SomeComponent>Hey I'm a child</SomeComponent>

Usage with children:

type ComponentWithChildrenProps = PropsWithChildren<{ a: string }>;

const ComponentWithChildrenProps: FC<ComponentWithChildrenProps> = ({
  a,
  children
}) => <div>{a} and {children}</div>

This allows to have a children prop a bit stricter. e.g.

type StrictCompProps = { children: string };

const StrictComp: FC<StrictCompProps> = ({ children }) => <div>{children}</div>;

// This will fail
<StrictComp><span>hey</span></StrictComp>
Sign up to request clarification or add additional context in comments.

12 Comments

Are you sure that <Images /> is functional component?
It isn't, getTabContent is. <Images /> is the return value of said functional component
Thank you @3Dos. But if I rewrite Image and Search to class components, I should change the type here and everywhere where these components are mentioned?
I think you don't get it. The functional component here is getTabContent and as long as it returns JSX values or null, it will be fine. In fact, the FC type here is not necessary as type inference will be enough. The FC type will allow you to use the children prop though but some devs like to always type with FC so each component is already typed.
I don't know if it was changed in a more recent version or not, but the full name is React.FunctionComponent and not React.FunctionalComponent.
|
54

If you want to use FunctionComponent with class Component, Then use React.ComponentType

Comments

20

Considering this built-in definition in React:

type PropsWithChildren<P> = P & {
    children?: React.ReactNode;
}

I am using React.ReactNode. It is defined as

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

2 Comments

React.ReactNode this is the thing I want everytime and I always forget 😅
This is the one!!!
5

TypeScript comes with powerful type inference. Just use it in most places. Only top-level components required fine-grained interfaces.

For example, here resulting type will be computed as JSX.Element

const getTabContent = ({ tab, onSelect }: { tab: number, onSelect: (ev: React.SyntheticEvent) => void }) => {
  switch (tab) {
    case 1:
      return <Image src="123"/>;
    default:
      return <Search onSelect={onSelect}/>;
  }
};

Comments

5

The best option would be ComponentType. If you are strict about the functional component, You can make use of FC. In some cases, You might want both class component type and functional component type support. (i.e. Defining a prop type where the prop is expecting a component, either functional or class).

The recommended way is to use ComponentType in the type definition (i.e. ProopTypes) and FC when you want to define return type etc.

FYI, Here is the definition of ComponentType, FC in typescript

type ComponentType<P = {}> = ComponentClass<P> | FunctionComponent<P>;
type FC<P = {}> = FunctionComponent<P>;

Comments

4

React.ReactNode is the correct way to define a React element type.

Comments

3

An easy sample of defining a component with type and using it in a different place:

step 1: define your component like this:

import React from "react";

const HomePage: React.FC = () => {
  return (
    <div>
      <h3>Home Page</h3>
    </div>
  );
};

export default HomePage;

step 2: define an interface in order to describe type of functional component:

export interface IRouteDto {
    id: number,
    path: string,
    faTitle: string
    element: React.FC,
}

step 3: use your interface easily:

export const routes: IRouteDto[] = [
    {id: 1, path:"/", faTitle: "خانه", element:HomePage}
    {id: 2, path:"/about", faTitle: "درباره ما", element:AboutPage},
    {id: 3, path:"/contact-us", faTitle: "تماس با ما", element:ContactUsPage},
]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.