Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React component type in TypeScript

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

like image 919
Gena Avatar asked Jul 09 '19 07:07

Gena


People also ask

What type is a React component?

React Components Components are independent and reusable bits of code. They serve the same purpose as JavaScript functions, but work in isolation and return HTML via a render() function. Components come in two types, Class components and Function components, in this chapter you will learn about Class components.

What is the type of React props TypeScript?

React has its own, built-in way of type checking called “prop types”. Together with TypeScript this provides a full, end-to-end type-checking experience: Compiler and run-time.

How do you define a component in TypeScript?

Using TypeScript, here's how we define the component: // Input. tsx import React from "react"; type Props = { onChange: (str: string) => void; placeholder: string; name: string; value?: string; }; function Input({ onChange, name, placeholder, value = "" }: Props) { return ( <input onChange={event => onChange(event.


4 Answers

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>
like image 104
3Dos Avatar answered Oct 16 '22 19:10

3Dos


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

like image 33
MJ Studio Avatar answered Oct 16 '22 20:10

MJ Studio


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;
like image 5
igo Avatar answered Oct 16 '22 18:10

igo


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}/>;
  }
};
like image 4
Alexander Alexandrov Avatar answered Oct 16 '22 19:10

Alexander Alexandrov