Type '({ items }: PropsWithChildren<TodoProps>) => Element[]' is not assignable to type 'FunctionComponent<TodoProps>'

homosaurus picture homosaurus · Nov 17, 2019 · Viewed 10.5k times · Source

I'm learning Typescript-react and I'm stuck in this error Type '({ items }: PropsWithChildren<TodoProps>) => Element[]' is not assignable to type 'FunctionComponent<TodoProps>' and I am lost on this.

Complete error:

Type '({ items }: PropsWithChildren<TodoProps>) => Element[]' is not assignable to type 'FunctionComponent<TodoProps>'.
  Type 'Element[]' is missing the following properties from type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)>': type, props, key

Link for code: sandbox repo.

Error happens on the declaration of TodoList function within the TodoList.tsx file.

Any help is appreciated. Cheers!


Code:

import React from "react";

interface Todo {
  id: number;
  content: string;
  completed: boolean;
}

interface TodoProps {
  items: Todo[];
}

//    v------v here is error
const TodoList: React.FC<TodoProps> = ({ items }) => {
  return items.map((item: Todo) => <div key={item.id}>{item.id}</div>);
};

export default TodoList;

Answer

ford04 picture ford04 · Nov 17, 2019

Yeah, the error may sound a bit confusing - in essence it says that you can only return a single ReactElement or its equivalent JSX.Element in the function component definition, enforced by React.FC type.

React Fragments solve this limitation, so you can write TodoList in the following manner:

interface TodoProps {
  items: Todo[];
}

const TodoList: React.FC<TodoProps> = ({ items }) => (
  <React.Fragment>
    {items.map((item: Todo) => (
      <div key={item.id}>{item.id}</div>
    ))}
  </React.Fragment>
);
Short form:
const TodoList: React.FC<TodoProps> = ({ items }) => (
  <>
    {items.map(({ id }) => <div key={id}>{id}</div>)}
  </>
);

By the way: With pure JS, both class and function components can return multiple elements in an array as render output. Currently, TS has a type incompatibility for returned arrays in function components, so Fragments provide a viable workaround here (in addition to type assertions).