问题
I have the following typescript code which uses a discriminated union to distinguish between some similar objects:
interface Fish {
type: 'FISH',
}
interface Bird {
type: 'BIRD',
flyingSpeed: number,
}
interface Ant {
type: 'ANT',
}
type Beast = Fish | Bird | Ant
function buildBeast(animal: 'FISH' | 'BIRD' | 'ANT') {
const myBeast: Beast = animal === 'BIRD' ? {
type: animal,
flyingSpeed: 10
} : {type: animal}
}
In the function buildBeast
it accepts a string that complies with all possible types
of my Beast
type, yet it does not allow me to declare the myBeast
as type Beast
due to this error:
Type '{ type: "BIRD"; flyingSpeed: number; } | { type: "FISH" | "ANT"; }' is not assignable to type 'Beast'.
Type '{ type: "FISH" | "ANT"; }' is not assignable to type 'Beast'.
Type '{ type: "FISH" | "ANT"; }' is not assignable to type 'Ant'.
Types of property 'type' are incompatible.
Type '"FISH" | "ANT"' is not assignable to type '"ANT"'.
Type '"FISH"' is not assignable to type '"ANT"'.
It seems that all cases still yield a correct Beast
yet TS seems to have trouble coercing the different types. Any ideas?
回答1:
TypeScript doesn't do control flow analysis by walking through union types and making sure that each type works. It would be nice if it did so or if you could tell it to do so, and in fact I've made a suggestion to that effect, but it isn't currently possible.
For now, the only way to deal with it that I know of are the workarounds I mention in that suggestion: either do a type assertion (which is unsafe) or walk the compiler through the different cases (which is redundant). Here are the two different ways:
Assertion:
function buildBeast(animal: 'FISH' | 'BIRD' | 'ANT') {
const myBeast: Beast = animal === 'BIRD' ? {
type: animal,
flyingSpeed: 10
} : {type: animal} as Fish | Ant;
}
Walk compiler through different cases:
function buildBeast(animal: 'FISH' | 'BIRD' | 'ANT') {
const myBeast: Beast = animal === 'BIRD' ? {
type: animal,
flyingSpeed: 10
} : (animal === 'FISH') ? {
type: animal
} : { type: animal };
}
Hey, if you think that TypeScript should allow you to distribute control flow analysis over union types, maybe head over to that suggestion and give it a 👍 or describe your use case. Or, if those above solutions work for you, that's great too.
Hope that helps. Good luck!
来源:https://stackoverflow.com/questions/51064527/defining-a-variable-as-one-variant-of-a-discriminated-union-in-typescript