Typescript: Value matching union type rejected

Created on 25 Oct 2018  路  1Comment  路  Source: microsoft/TypeScript


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.

Design Limitation

Most helpful comment

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 }.

>All comments

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 }.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Gaelan picture Gaelan  路  231Comments

kimamula picture kimamula  路  147Comments

jonathandturner picture jonathandturner  路  147Comments

sandersn picture sandersn  路  265Comments

quantuminformation picture quantuminformation  路  273Comments