I am trying to write a Higher Order Component in React using Typescript that receives the props, 'consumes' one of them and then passes on the remainder to the Child component.
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;
}
However this fails with the error: 'Pick<LAP, Exclude<keyof T, "iS">>' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'
I would like to know not only if there's anything I can do about it, but also why this happens at all.
Actually, Typescript is catching a Problem with your component:
const Component = testConnect(({ iS }) => <div>{iS}</div>);
<Component iS={...} />
So you either have to
(a) pass on all props (instead of just rest) to the component.
<Child {...props} />
(b) Make sure that no prop named "iS" can be passed in by excluding the key iS
from T:
testConnect<T>(Child: React.ComponentType<Omit<T, "iS">>>): React.ComponentType<T> {
Here is a solution to your problem, not the most elegant one, but it stops to complain:
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;
}
To your code stops to complain, you need to fix how you are passing the props to the Child
component. He accepts props
of type T
. But rest
in your case is not of type T
(or at least TS compiler is not smart enough to figure it out), its type is Pick<LAP, Exclude<keyof T, "iS">>
because of the rest operator
you used.
My solution idea is just to let the compiler knows that rest
is of type T
, using a custom type guard function, but you could use other approaches, like a type casting:
<Child
{...((rest as unknown) as T)}
/>
I hope it helps you!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With