-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TS2345 error with discriminated unions #17480
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: