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!
