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