javascript - Spread-operator med React Props i Typescript (feil: ...kan bli instansiert med en annen undertype av begrensning {})


Jeg prøver å skrive en Higher Order Component i React ved å bruke Typescript som mottar props, 'konsumerer' en av dem og deretter sender resten videre til Child-komponenten.

function testConnect<T>(Child: React.ComponentType<T>): React.ComponentType<T> {

  type InitialState = {
    iS: StoreShape.State;
  };

  type LAP = InitialState & T;

  const Connector = (props: LAP) => {
    const { iS, ...rest } = props;
    // do something with iS
    return (
      <Child // Visual Studio complains about this line.
        {...rest}
      />
    );
  };

  return Connector;
}

Dette mislykkes imidlertid med feilen: 'Pick<LAP, Exclude<keyof T, "iS">>' kan tildeles begrensningen av typen 'T', men 'T' kan bli instansiert med en annen subtype av begrensningen '{}'

Jeg vil gjerne vite ikke bare om det er noe jeg kan gjøre med det, men også hvorfor dette skjer i det hele tatt.

Svar #1

Faktisk fanger Typescript et problem med komponenten din:

 const Component = testConnect(({ iS }) => <div>{iS}</div>);

 <Component iS={...} />

Så du må enten

(a) send videre alle egenskaper (i stedet for bare resten) til komponenten.

   <Child   {...props} />

(b) Sørg for at ingen prop kalt «iS» kan sendes inn ved å utelate nøkkelen iS fra T:

 testConnect<T>(Child: React.ComponentType<Omit<T, "iS">>>): React.ComponentType<T> {

Svar #2

Her er en løsning på problemet ditt, ikke den mest elegante, men den slutter å klage:

type InitialState = {
    iS: StoreShape.State;
};

function testConnect<T>(Child: React.ComponentType<T>): React.ComponentType<T> {
    const Connector = (props: InitialState & Exclude<T, "iS">) => {
        const isT = (object: any): object is T => {
            return !("iS" in object);
        };

        const { iS, ...rest } = props;

        if (isT(rest)) {
            return (
                <Child // Visual Studio complains on this line.
                    {...rest}
                />
            );
        }

        return <Child {...props} />;
    };

    return Connector;
}

For at koden din skal slutte å klage, må du fikse hvordan du sender props til Child-komponenten. Den aksepterer props av typen T. Men rest i ditt tilfelle er ikke av typen T (eller i det minste er ikke TS-kompilatoren smart nok til å finne det ut), dens type er Pick<LAP, Exclude<keyof T, "iS">> på grunn av rest-operatoren du brukte.

Min løsningsidé er bare å la kompilatoren vite at rest er av typen T, ved å bruke en egen typebeskyttelsesfunksjon, men du kan bruke andre tilnærminger, som for eksempel typekasting:

<Child
  {...((rest as unknown) as T)}
/>

Jeg håper det hjelper deg!

Relaterte artikler