Home > Back-end >  Combining results of Pick and Omit on the same keys fails typecheck
Combining results of Pick and Omit on the same keys fails typecheck

Time:04-07

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            
  • Related