Why does the following code fail to typecheck?
const fun = <T, S extends keyof T>(
a: Pick<T, S>,
b: Omit<T, S>
): T => ({ ...a, ...b })
I get the following error:
Type 'Pick<T, S> & Omit<T, S>' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'Pick<T, S> & Omit<T, S>'.
It works when I specify the keys to Pick/Omit, but for some reason it doesn't work when it's a generic.
CodePudding user response:
This is currently a missing feature of TypeScript; see microsoft/TypeScript#28884. The compiler is not able to perform the higher order type analysis necessary to see that Pick<T, K> & Omit<T, K>
should be assignable to T
when T
and/or K
are generic type parameters. For any specific T
and K
the compiler can structurally verify the equivalence, but for generic T
or K
the compiler mostly just defers evaluation. From the relevant comment:
the core problem is that an intersection of complementary subsets of a higher order type, constructed using
Pick<T, K>
or by other means, is not assignable back to that higher order type.
For now, until and unless the feature requested at microsoft/TypeScript#28884 is implemented, you'll need to use something like a type assertion to tell the compiler that you're sure it works (because the compiler is not sure):
const fun = <T, K extends keyof T>(
a: Pick<T, K>,
b: Omit<T, K>
) => ({ ...a, ...b } as T) // no error