I have the following code:
type XType<T> = {
x: T;
};
function extractTypes<Props, T>(Component: React.FC<Props & XType<T>>) {
return (props: Props, value: T) => {
Component({ ...props, x: value });
};
}
const CompA: React.FC<{ a: string } & XType<string>> = () => <div>HELLO</div>;
const CompB: React.FC<{ b: string } & XType<number>> = () => <div>WORLD</div>;
extractTypes<{ a: string }, string>(CompA)({ a: 'A' }, 'X'); // OK
extractTypes<{ b: string }, number>(CompB)({ b: 'B' }, 1); // OK
extractTypes(CompA)({ a: 'A' }, 'X'); // Compile error
extractTypes(CompB)({ b: 'B' }, 1); // Compile error
CompA and CompB expect a and b properties along with all properties in XType.
The 3rd-last and 4th-last compile correctly, however the Typescript compiler complains on the last two lines as follows:
Argument of type '{ a: string; }' is not assignable to parameter of type 'PropsA & XType<string>'.
Property 'x' is missing in type '{ a: string; }' but required in type 'XType<string>'.ts(2345)
Argument of type '{ b: string; }' is not assignable to parameter of type '{ b: string; } & XType<number>'.
Property 'x' is missing in type '{ b: string; }' but required in type 'XType<number>'.ts(2345)
I've tried many approaches to ensure that I can call extractTypes without specifying the types explicitly and still ensure that the method returned by this function accepts only { a: string } or { b: string } instead of { a: string; x: string } or { b: string; x: number }, but to no avail.
Is there any way I can accomplish this without requiring explicit specifying generic types for extractTypes?
I think I need to find a way to create a type by subtracting one type (XType) from another (Props). I've tried using Omit<Props, keyof XType<T>> but it doesn't work well here.
Thanks!
Asim
I would simply extend
XType. This will force you to assert a type internally though.playground
If you want excess property checking to also work when you pass a reference as props, you can use
Omit<Props, keyof XType> & {[k in keyof XType]?: never}but this may be overkill given the way people use React.As a side-note, merging the 2 generics was not strictly necessary and your original design is safer, because removing
x: valuewill yield an errorI don't know why though because
Propsis inferred as{a: string} & XType<string