Components with function declarations and TypeScript

— 4 minute read

For React functional component written with TypeScript there is a nice type provided by @types/react:

import React from 'react';

interface Props {
someProp?: boolean;
}

let MyComponent: React.FC<Props> = function({ someProp, children }) {
return <>{someProp ? children : null}</>;
}

It takes care of children prop, describes return type, and also provides types for React component properties like defaultProps and displayName.

This type works only with function expression syntax. I was looking for a way how to get the same benefits (or most of them) with function declaration syntax, which I found more readable. Unfortunately, I couldn't find anything, because all articles and Stack Overflow were talking about function expression syntax only. There was a question on Stack Overflow about function declarations, but it didn't cover everything I need. The most important part for me was to figure out how to type children prop, and what return type should be.

First step to figure out how to make it work was looking into React.FC type:

type FC<P = {}> = FunctionComponent<P>;

interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}

We see that React.FC props are PropsWithChildren type:

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

From these two findings we understand:

  • Return type should be ReactElement | null.
  • children prop type is ReactNode.

Combining this knowledge, we get the following React component:

import React from 'react';

interface Props {
someProp?: boolean;
children: React.ReactNode;
}

function MyComponent({ children, someProp }: Props): React.ReactElement | null {
return <>{someProp ? children : null}</>;
}

We could simplify this by letting TypeScript infer return type:

import React from 'react';

interface Props {
someProp?: boolean;
children: React.ReactNode;
}

function MyComponent({ children, someProp }: Props) {
return <>{someProp ? children : null}</>;
}

TypeScript infer return type as JSX.Element, which is an alias for ReactElement.

My use cases are covered with this. Most of the time I wouldn't need to add any specific React types, and only need to add type for children. There are might be things that I'm missing, because I'm very new to TypeScript. But so far so good. I've been using it for more than a month, and have no type issues with this approach.