Typescript: Union with non-distinct discriminating property breaks inference somewhat (confusing error messages, invalid intellisense)

Created on 4 Oct 2020  ·  3Comments  ·  Source: microsoft/TypeScript


TypeScript Version: 4.0.2


Search Terms: discriminated union, error messages

Code

type Action = {
    type: 'action1';
    payload: {
        property1: string;
    };
} | {
    type: 'action1';
    payload: {
        property2: number;
    };
} | {
    type: 'action2';
    payload: {
        property3: boolean;
    };
}

const action: Action = { // Actual error is here
    type: 'action1',
    payload: {
        property3: true // Expected error here
    }
}

Expected behavior:

Expected error at action.payload.property3 declaration, perhaps something like:

Object literal may only specify known properties, and 'property3' does not exist in type '{ property1: string; } | { property2: number; }'.

Also, once the object has been refined by the type action1, intellisense should only provide property1 and property2 as a suggestion when declaring the payload.

Actual behavior:

An error message at the first line of the declaration:

Type '{ type: "action1"; payload: { property3: true; }; }' is not assignable to type 'Action'.
  Type '{ type: "action1"; payload: { property3: true; }; }' is not assignable to type '{ type: "action2"; payload: { property3: boolean; }; }'.o
      Type '"action1"' is not assignable to type '"action2"'.(2322)

Also, once the object has been refined by the type action1, intellisense still provides property3 as a suggestion when declaring the payload.

Playground Link: https://www.typescriptlang.org/play?#code/C4TwDgpgBAggxsAlgewHZQLxQN4CgoFSiQBcUA5AIYIqoCM5A3PoWJSADbKUAmZehQVDAAnZJBGg6ZAM7ARiVAHNmggL7M1UAD44WBYhDJUaaBqtbsuvfvqGjxESSABMZVAFcAtgCMnFgg1cLV0BQkNjaiQ0FyY7Nk5uPj0hVjEJUABmMh9kZA4ISlQAqCC1XFw4NDkoKNoyeGj0LDCDcCMKOrNyABp4qyTbVIIHDJBsohEPCDtytSA

Bug Completion Lists

Most helpful comment

I think it is similar to this https://github.com/microsoft/TypeScript/issues/39438 issue related to contextual type in a completion list

All 3 comments

I expect this would all work out fine if somehow TypeScript could reduce:

type Action = {
    type: 'action1';
    payload: {
        property1: string;
    };
} | {
    type: 'action1';
    payload: {
        property2: number;
    };
} | {
    type: 'action2';
    payload: {
        property3: boolean;
    };
}

To:

type Action = {
    type: 'action1';
    payload: {
        property1: string;
    } | {
        property2: number;
    };
} | {
    type: 'action2';
    payload: {
        property3: boolean;
    };
}

Although, I don't know enough to be sure that is a valid reduction all of the time.

The completions bit does seem like a bug, and I 100% agree with your logic about the error message, though I’m not super optimistic that it can easily be generalized. Worth taking a look, though. (cc @DanielRosenwasser for thoughts on error elaboration)

I think it is similar to this https://github.com/microsoft/TypeScript/issues/39438 issue related to contextual type in a completion list

Was this page helpful?
0 / 5 - 0 ratings

Related issues

blendsdk picture blendsdk  ·  3Comments

weswigham picture weswigham  ·  3Comments

manekinekko picture manekinekko  ·  3Comments

fwanicka picture fwanicka  ·  3Comments

CyrusNajmabadi picture CyrusNajmabadi  ·  3Comments