reactjs - Hvordan passer man dynamiske props til en React-komponent, der accepterer en union af objekter som dens type?


Jeg vil have en komponent til at videresende dynamiske props (jeg bruger spread-operatoren), og dette er den kode, jeg har lige nu:

type Props = {
  identifier: "YouTube";
  attributes: { id: string };
} | {
  identifier: "Figure";
  attributes: { src: string };
};

const YouTube = ({ id }) => <p>{id}</p>;
const Figure = ({ src }) => <p>{src}</p>;

const Shortcode = ({ identifier, attributes }: Props): JSX.Element => {
  switch (identifier) {
    case "YouTube":
      return <YouTube {...attributes} />;
    case "Figure":
      return <Figure {...attributes} />;
  }
};

TypeScript klager over dette:

return <YouTube {...attributes} />;
// Type '{ id: string; } | { src: string; }' is not assignable to type 'IntrinsicAttributes & { id: any; }'.
//   Property 'id' is missing in type '{ src: string; }' but required in type '{ id: any; }'.ts(2322)

return <Figure {...attributes} />;
// Type '{ id: string; } | { src: string; }' is not assignable to type 'IntrinsicAttributes & { src: any; }'.
//   Property 'src' is missing in type '{ id: string; }' but required in type '{ src: any; }'.ts(2322)

Hvis jeg eksplicit videregiver props, opfører TypeScript sig som forventet:

<YouTube id="foo" />      // TS says this is ok
<YouTube wrong="props" /> // TS says this is missing the `id` prop

Men jeg har brug for, at det kan acceptere dynamiske props. Nogle idéer til, hvordan man løser dette? Tak.

Svar #1

Dette skyldes destrukturering. TS behandler dem ikke som en del af en union.

For at gøre TS glad, skal du bare ikke bruge destrukturering:

import React, { FC } from 'react';


type Props = {
    identifier: "YouTube";
    attributes: { id: string };
} | {
    identifier: "Figure";
    attributes: { src: string };
};

const YouTube: FC<{ id: string }> = ({ id }) => <p>{id}</p>;
const Figure: FC<{ src: string }> = ({ src }) => <p>{src}</p>;

const Shortcode = (props: Props): JSX.Element => {
    switch (props.identifier) {
        case "YouTube":
            return <YouTube {...props.attributes} />; // ok
        case "Figure":
            return <Figure {...props.attributes} />; // ok
    }
};

Relaterede artikler