TypeScript Version: [email protected]
Search Terms: union narrowing discriminate missing property field
Code
enum Foo
{
A,
B,
C
}
type Bar = {
foo: Foo.A;
bar: string;
} | {
foo: Foo.B;
bar?: string;
} | {
foo: Foo.C
};
function fn(bar: Bar): Bar
{
if (bar.foo != Foo.A)
{
const newValue = {
foo: bar.foo
};
return newValue;
}
}
Expected behavior:
fn compiles without errors.
Actual behavior:
Type '{ foo: Foo.B | Foo.C; }' is not assignable to type 'Bar'.
Type '{ foo: Foo.B | Foo.C; }' is not assignable to type '{ foo: Foo.C; }'.
Types of property 'foo' are incompatible.
Type 'Foo.B | Foo.C' is not assignable to type 'Foo.C'.
Type 'Foo.B' is not assignable to type 'Foo.C'.
Playground Link: https://www.typescriptlang.org/play/index.html#src=enum%20Foo%0D%0A%7B%0D%0A%09A%2C%0D%0A%09B%2C%0D%0A%09C%0D%0A%7D%0D%0A%0D%0Atype%20Bar%20%3D%20%7B%0D%0A%09foo%3A%20Foo.A%3B%0D%0A%09bar%3A%20string%3B%0D%0A%7D%20%7C%20%7B%0D%0A%09foo%3A%20Foo.B%3B%0D%0A%09bar%3F%3A%20string%3B%0D%0A%7D%20%7C%20%7B%0D%0A%09foo%3A%20Foo.C%0D%0A%7D%3B%0D%0A%0D%0Afunction%20fn(bar%3A%20Bar)%3A%20Bar%0D%0A%7B%0D%0A%09if%20(bar.foo%20!%3D%20Foo.A)%0D%0A%09%7B%0D%0A%09%09return%20%7B%0D%0A%09%09%09foo%3A%20bar.foo%0D%0A%09%09%7D%3B%0D%0A%09%7D%0D%0A%7D
Related Issues: #28138
{ foo: A | B } should be assignable to { foo: A } | { foo: B }... It seems obvious that the types are equivalent...
The check would be something along the lines of:
{ foo: A | B } can be either { foo: A } or { foo: B }, each of these is assignable to { foo: A } | { foo: B }.
Therefore, they are assignable.
This is basically:
function f(a: 1 | 2): { a: 1 } | { a: 2 } {
return { a };
}
We don't distribute a union type of an object so can't detect that { a: 1 | 2 } should be assignable to { a: 1 } | { a: 2 }.
Most helpful comment
This is basically:
We don't distribute a union type of an object so can't detect that
{ a: 1 | 2 }should be assignable to{ a: 1 } | { a: 2 }.