CodeG
CodeG

Reputation: 467

TypeScript - Type 'undefined' is not assignable to type 'ReactElement'

I'm having this error output in my react project

TypeScript error
Argument of type 'ReactNode' is not assignable to parameter of type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactElement<any, string | JSXElementConstructor<any>>[]'.
  Type 'undefined' is not assignable to type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactElement<any, string | JSXElementConstructor<any>>[]'.

But I can't find out exactly what's wrong with my code, here's:

           const { children } = props;

  > 19 |   const mapChildren = React.Children.map(children, (tread: ReactElement) => tread);
       |                                          ^
    20 |   const child = mapChildren.filter((tread: ReactElement) => tread.props.id === currentTread)[0];
    21 | 
    22 |     useEffect(() => {
              init(mapChildren);
             }, []);

What exactly is wrong with the children element?

Upvotes: 0

Views: 2126

Answers (1)

rsmeral
rsmeral

Reputation: 576

Fix

This is sufficient and type-safe:

const mapChildren = React.Children.map(children, (tread) => tread);

The type of tread is prescribed by Children.map and inferred by TypeScript.

Why?

Nothing is wrong with children as such.

But we have to ensure that the type of children matches the type of the function passed to Children.map:

map<T, C>(
  children: C | C[], 
  fn: (child: C, index: number) => T
): C extends null | undefined 
  ? C 
  : Array<Exclude<T, boolean | null | undefined>>;

(Source)

This means that the type of the child argument of fn has to be the same as the type of children (regardless of whether children is a single object or an array).

What happens when we pass (tread: ReactElement) => tread as fn?

We're saying that fn will only accept children that are ReactElements.

However, children are ReactNodes (unless you explicitly type it differently), so React can't pass them through fn because of the type mismatch.

What's the type mismatch?

ReactElement is just one of several possible types of ReactNode:

  • type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined
  • type ReactChild = ReactElement | ReactText

So, why that error? (undefined is not assignable to ReactElement)?

The error means "A child might be of type undefined but the function you passed to map won't accept that."

undefined is the last type in the definition of ReactNode and in union types, that's (apparently) what TypeScript does – only complains about the last incompatible type.

Upvotes: 2

Related Questions