DEV Community

Cover image for React.FC is fixed?
Cibi Aananth
Cibi Aananth

Posted on • Originally published at blog.asciibi.dev

React.FC is fixed?

React.FC was removed from create-react-app in Jan 2020 due to two drawbacks, but with the release of TypeScript 5.1 and React 18, these issues have been resolved, allowing components to return various types without errors and improving type safety.

React.FC received love and hate from the React community and at some point it was criticized enough to get itself removed from create-react-app back on Jan 23, 2020. But why?

  1. Cannot type components returning undefined, string or number although it is a perfectly valid syntax.

  2. Implicitly includes children in props type

Now with the latest release of TypeScript 5.1 and React 18, it no longer displays those squiggly red lines.

What does that mean?

Let's take an example of a functional component that returns a string,

const Greet: React.FC = () => {
  return "Hello World"
};
Enter fullscreen mode Exit fullscreen mode

before TypeScript 5.1 and React 18, this would throw an error as
Type '() => string' is not assignable to type 'FC<{}>'. Type 'string' is not assignable to type 'ReactElement<any, any>'.ts(2322)
But now with a newer version, this is a perfectly valid syntax.

Another example covering the 2nd drawback of React.FC,

const Button: React.FC = () => {
  return <button>Click me</button>;
};

export const App = () => {
  <Button>Boop</Button>; // valid syntax
};
Enter fullscreen mode Exit fullscreen mode

In the above example, the Button component does not accept children but TypeScript doesn't warn you if you try to provide children Boop like <Button>Boop</Button>

Now with the newer versions, the above code would throw an error as

Type '{ children: string; }' has no properties in common with type 'IntrinsicAttributes'.ts(2559)

What changed?

Well, React fixed these typings by replacing the return type of React.FC from React.ReactElemet to React.ReactNode

What's the difference?

React.ReactElement type is defined as,

interface ReactElement<
  P = any,
  T extends string | JSXElementConstructor<any> =
    | string
    | JSXElementConstructor<any>
> {
  type: T;
  props: P;
  key: Key | null;
}
Enter fullscreen mode Exit fullscreen mode

which means that it breaks when you attempt to pass in a string, number, or undefined as a child.

Whereas React.ReactNode is defined as a type that accepts all possible types that React can render.

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

type ReactFragment = {} | Iterable<ReactNode>;
type ReactText = string | number;
type ReactChild = ReactElement | ReactText;
interface ReactPortal extends ReactElement {
  key: Key | null;
  children: ReactNode;
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

In conclusion, the latest TypeScript 5.1 and React 18 updates have addressed the issues with React.FC, allowing components to return various types such as strings, numbers, and undefined without errors. This improvement enhances the developer experience and ensures better type safety when using functional components in React applications.

Top comments (0)