Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.Children.toArray can't find props on children using typescript

Typescript can't detect props object on children using React.Children.toArray I have to use any[] because if I use ReactChild[] - props is not detected on an array item. How do I correctly type this out? Thanks!

const items: any[] = React.Children.toArray(this.props.children)

// select whatever item was told to be onload first
const itemPaymentType = items[0].props['data-payment']

enter image description here

like image 595
Spencer Bigum Avatar asked Sep 26 '18 18:09

Spencer Bigum


People also ask

How do you use children props in TypeScript?

By invoking them between the opening and closing tags of a JSX element, you can use React children for entering data into a component. The React children prop is an important concept for creating reusable components because it allows components to be constructed together.

What does React children toArray do?

Children. toArray. Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.


2 Answers

casieber answer is correct.

but in order to access your props with typescript, this is needed:

const item = items[0];
if (React.isValidElement<{prop1: boolean}>(item)) {

    // item.props.prop1 -- works
}
like image 152
Uzi Avatar answered Oct 23 '22 00:10

Uzi


Typescript is doing the right thing here. Take a look at the typings definition for ReactChild:

type ReactChild = ReactElement<any> | ReactText;

where ReactText is typed as string | number.

By saying const items: ReactChild[] you are telling TypeScript that items is an array that has elements that are possibly strings. Obviously, a string does not have props as a property, and so it is complaining, rightly so, when you try and use props.

If you are certain that your component's children will only ever be true elements containing the prop types you are looking for, then you can type the output as ReactElement<P> where P is the prop types you expect. However, doing so is essentially casting something that you haven't guaranteed. A better way might be to allow TypeScript type inference to come into play through somethign like the following:

const items = React.Children.toArray(this.props.children); // Will be ReactChild[]

const item = items[0];
if (typeof item === 'string' || typeof item === 'number') {
    console.error('Expecting component children to be of type ...');
} else {
    // At this point, TypeScript will know that item must be of type ReactElement
    // since you have already taken care of the number and string case
    const itemPaymentType = item.props['data-payment'];
    // ...
}
like image 45
casieber Avatar answered Oct 22 '22 22:10

casieber