-
Notifications
You must be signed in to change notification settings - Fork 12.8k
TS2345 error with discriminated unions #17480
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
Additional informations trying to use this function: const fun = (a: TodosAction) => {
} with const action = {
type: 'TOGGLE_TODO',
id: 1
}
fun(action)
^^^^^^ Calling function with a plain javascript object (inlining action variable) it works like expected: fun({
type: 'TOGGLE_TODO',
id: 1
}) |
You have to use type assertion for literal types in object, otherwise TS will widen them into their super-type, e.g. const action1 = {
type: 'TOGGLE_TODO',
id: 1
}; //=> { type: string, id: number }
const action2 = {
type: 'TOGGLE_TODO' as 'TOGGLE_TODO',
id: 1
}; //=> { type: 'TOGGLE_TODO', id: number }
const action3 = {
type: 'TOGGLE_TODO',
id: 1 as 1
}; //=> { type: string, id: 1 }
const action4 = {
type: 'TOGGLE_TODO' as 'TOGGLE_TODO',
id: 1 as 1
}; //=> { type: 'TOGGLE_TODO', id: 1 } |
Of course, but in some cases TS can handle properly type inference with no type assertion for literal types needed fun({
type: 'TOGGLE_TODO',
id: 1
}) // => works probabily I'm missing something: but I was expecting to do type assertion for literals in any cases (or - even better - in no case) |
Hmm, is there no other way to work around this? The source of the input is JSON, which means I don't have control over it so I can't do the |
My issue (and the one mentioned here) can be worked around by being explicit about the type on original assignment:
|
I still feel like a workaround that would be correct and intuitive would be to write const action1 = {
get type() { return 'TOGGLE_TODO'; },
id: 1
}; since it creates a value with an immutable I proposed this in #11467 but I believe it was either declined or there was little interest in it. It is also, in my view, inconsistent since if you specify @MicahZoltu FYI, you can use ```ts to make you code blocks highlight correctly. |
Maybe I'm asking the obvious, but why not annotate const action: TodosAction = {
type: 'TOGGLE_TODO',
id: 1
}; Literal types are not inferred, unless TS knows it's your intention to do so. This can be achieved either by type assertions, type annotations or other forms of context. |
In my code actually I'm annotatin action and is very verbose. I know that literal types are not inferred, unless TS knows it's my intention to do so, but TS infer correcly in case of inline: fun({
type: 'TOGGLE_TODO',
id: 1
}) but not when a variable in involved: const action = {
type: 'TOGGLE_TODO',
id: 1
}
fun(action)
^^^^^^ The TS error is on the last row, where the intention is as clear as the inline version; in my opinion if TS can infer type on the first case, could infer types on the second too. |
When you are provide the object inline as in const userComment = {
userName: 'john_doe',
message: 'Hello world'
};
// for security reasons hide the username
userComment.useName = userComment.useName.slice(0, 3) + '...'; Should Speaking of discriminated unions, I use constructor functions to help the compiler out and spare myself some writing: interface ToggleTodoAction { type: 'TOGGLE_TODO', id: number }
interface AddTodoAction { type: 'ADD_TODO', id: number, text: string }
type TodosAction = AddTodoAction | ToggleTodoAction
function mkToggleTodo(id: number): ToggleTodoAction {
return { type: 'TOGGLE_TODO', id };
}
function mkAddTodo(id: number, text: string): AddTodoAction {
return { type: 'ADD_TODO', id, text };
}
const action = mkToggleTodo(1); |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
TypeScript Version: 2.4.2
Code
Expected behavior:
No error.
Actual behavior:
The text was updated successfully, but these errors were encountered: