Estoy tratando de aprovechar el soporte agregado recientemente para escribir niños en el compilador TypeScript y @types/react, pero tengo problemas. Estoy usando TypeScript versión 2.3.4.
Digamos que tengo un código como este:
interface TabbedViewProps {children?: Tab[]} export class TabbedView extends React.Component<TabbedViewProps, undefined> { render(): JSX.Element { return <div>TabbedView</div>; } } interface TabProps {name: string} export class Tab extends React.Component<TabProps, undefined> { render(): JSX.Element { return <div>Tab</div> } }Cuando trato de usar estos componentes así:
return <TabbedView> <Tab name="Creatures"> <div>Creatures!</div> </Tab> <Tab name="Combat"> <div>Combat!</div> </Tab> </TabbedView>;Me sale un error de la siguiente manera:
ERROR in ./src/typescript/PlayerView.tsx (27,12): error TS2322: Type '{ children: Element[]; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<TabbedView> & Readonly<{ children?: ReactNode; }> ...'. Type '{ children: Element[]; }' is not assignable to type 'Readonly<TabbedViewProps>'. Types of property 'children' are incompatible. Type 'Element[]' is not assignable to type 'Tab[] | undefined'. Type 'Element[]' is not assignable to type 'Tab[]'. Type 'Element' is not assignable to type 'Tab'. Property 'render' is missing in type 'Element'. Parece estar infiriendo el tipo de elementos secundarios como Element[] en lugar de Tab[] , aunque ese es el único tipo de elementos secundarios que estoy usando.
EDITAR: También estaría bien restringir la interfaz de los accesorios secundarios en lugar de restringir el tipo de componentes secundarios directamente, ya que todo lo que necesito hacer es extraer algunos accesorios específicos de los componentes secundarios.
Edición 2: resulta que este enfoque evita la advertencia, pero según los comentarios, TabProps no se verifica correctamente.
Deberías intentar configurar elementos secundarios de la interfaz TabbedViewProps así
interface TabbedViewProps { children?: React.ReactElement<TabProps>[] } La idea aquí no es decirle a su TabbedView que tiene una matriz de Tab , sino decirle a su TabbedView que tiene una matriz de element que toman accesorios específicos. En su caso TabProps .
Editar (gracias a Matei):
interface TabbedViewProps { children?: React.ReactElement<TabProps>[] | React.ReactElement<TabProps> }Como ya se señaló, declarar TabbedView.children como:
children: React.ReactElement<TabProps> | React.ReactElement<TabProps>[]; Eliminará el error, pero no verificará correctamente el tipo de niños. Es decir, aún podrá pasar elementos secundarios que no sean TabProps a TabbedView sin obtener ningún error, por lo que esto también sería válido:
return ( <TabbedView> <Tab name="Creatures"> <div>Creatures!</div> </Tab> <Tab name="Combat"> <div>Combat!</div> </Tab> <NotTabButValidToo /> </TabbedView> ); Lo que podría hacer en su lugar es declarar un accesorio, digamos tabs: TabProps[] , para transmitir los accesorios que necesita para crear esas Tab , en lugar de su JSX, y renderizarlas dentro TabbedView :
interface TabbedViewProps { children?: never; tabs?: TabProps[]; } ... const TabbedView: React.FC<TabbedViewProps > = ({ tabs }) => { return ( ... { tabs.map(tab => <Tab key={ ... } { ...tab } />) } ... ); };Traté de afirmar el tipo. Puedes tirar o simplemente ignorar.
interface TabbedViewProps { children?: React.ReactElement<ITabProps> | React.ReactElement<ITabProps>[] }Y en el componente mismo mapear a los niños y afirmar o ignorar
{React.Children.map(props.children, (tab) => { if(tab?.type != Tab) return; console.log(tab?.type == Tab); return tab; })}