Shouldn't Omit<T, keyof U> & U be equal to just T? Or am I missing something?
Here is an example, where this issue arises:
interface Bar {
bar: string;
}
class Foo<T extends Bar> {
foo(obj: Omit<T, keyof Bar>): T {
return { ...obj, bar: 'bar' }; // compile error
}
}
This is the error message from the Typescript compiler:
Type Pick<T, Exclude<keyof T, "bar">> & { bar: string; } is not assignable to type T.
Pick<T, Exclude<keyof T, "bar">> & { bar: string; } is assignable to the constraint of type T, but T could be instantiated with a different subtype of constraint Bar.
Of course one could simply cast it and it would work. Like so:
class Foo<T extends Bar> {
foo(obj: Omit<T, keyof Bar>): T {
return { ...obj, bar: 'bar'} as T; // this works
}
}
But should this casting be necessary?
The expression { ...obj, bar: 'bar' } is inferred to be Omit<T, keyof Bar> & Bar. But, after all, is that not an alias for T? How could T ever be instantiated with a different subtype of constraint Bar?
To summarize,
if Omit<T, keyof Bar> is picking every member of T, excluding the one's existing in Bar,
How is the intersection of the types Omit<T, keyof Bar> and Bar not just T?