reactjs - Kuinka rajoitan React-lasten tyypin TypeScriptissä käyttämällä uudelleen TypeScript 2.3:ssa lisättyä tukea?


Yritän hyödyntää äskettäin lisättyä tukea lasten tyypittämiseen TypeScript-kääntäjässä ja @types/reactissä, mutta minulla on vaikeuksia. Käytän TypeScriptin versiota 2.3.4.

Sano, että minulla on koodi, joka näyttää tältä:

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>
  }
}

Kun yritän käyttää näitä komponentteja näin:

return <TabbedView>
  <Tab name="Creatures">
    <div>Creatures!</div>
  </Tab>
  <Tab name="Combat">
    <div>Combat!</div>
  </Tab>
</TabbedView>;

Saan seuraavan virheilmoituksen:

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'.

Näyttää siltä, että se päättelee lasten tyypin vain Element[]:ksi Tab[]:n sijaan, vaikka se on ainoa käyttämäni lasten tyyppi.

MUOKKAA: Olisi myös täysin sopivaa rajoittaa children-propsien rajapintaa sen sijaan, että rajoitettaisiin suoraan lasten komponenttien tyyppiä, koska ainoa mitä minun tarvitsee tehdä, on ottaa tietyt propsit irti lasten komponenteista.

Vastaus #1

Muokkaus 2: Käy ilmi, että tämä lähestymistapa estää varoituksen, mutta kommenttien mukaan TabProps ei ole tarkistettu oikein.

Sinun pitäisi yrittää asettaa interface TabbedViewProps:n lapset näin

interface TabbedViewProps { children?: React.ReactElement<TabProps>[] }

Tässä ei ole tarkoitus kertoa TabbedView -komponentillesi, että sillä on taulukko Tab-elementtejä, vaan sen sijaan kertoa TabbedView -komponentillesi, että sillä on taulukko element-elementtejä, jotka ottavat tietyt ominaisuudet. Tapauksessasi TabProps.

Muokkaa (kiitos Mateille):

interface TabbedViewProps {
    children?: React.ReactElement<TabProps>[] | React.ReactElement<TabProps>
}

Vastaus #2

Kuten jo mainittiin, TabbedView.children määritellään seuraavasti:

children: React.ReactElement<TabProps> | React.ReactElement<TabProps>[];

Poistaa virheen, mutta ei tarkista lasten tyyppejä oikein. Toisin sanoen voit silti antaa lapsia, jotka eivät ole TabProps, TabbedView-komponentille ilman virhettä, joten tämä olisi myös voimassa:

return (
  <TabbedView>
    <Tab name="Creatures">
      <div>Creatures!</div>
    </Tab>

    <Tab name="Combat">
        <div>Combat!</div>
    </Tab>

    <NotTabButValidToo />
  </TabbedView>
);

Mitä voisit sen sijaan tehdä, on julistaa prop, sanotaan vaikka tabs: TabProps[], jotta voit välittää alas propsit, joita tarvitset näiden Tabien luomiseen, sen sijaan että välität niiden JSX:n, ja renderöidä ne sisälle TabbedViewiin:

interface TabbedViewProps {
  children?: never;
  tabs?: TabProps[];
}

...

const TabbedView: React.FC<TabbedViewProps> = ({ tabs }) => {
  return (
    ...

    { tabs.map(tab => <Tab key={ ... } { ...tab } />) }

    ...
  );
};

Aiheeseen liittyviä artikkeleita