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
?