考虑我们有一个联合类型,它代表三个不同的字符串值之一。
type Animal = 'bird' | 'cat' | 'dog';
现在我想创建一只狗并检查它是哪种动物来产生正确的噪音。
let oscar: Animal = 'dog';
switch (oscar) {
case 'bird':
console.log('tweet');
break;
case 'cat':
console.log('meow');
break;
case 'dog':
console.log('bark');
break;
}
此代码将导致 TypeScript 错误:
Type '"bird"' is not comparable to type '"dog"'.ts(2678)
(与猫类比)。但是,如果我对变量 oscar
使用显式类型转换,它可以正常工作:switch (oscar as Animal) {
case 'bird':
...
case 'cat':
...
case 'dog':
...
}
如果我对
oscar
使用显式值,您能否向我解释为什么前两个 switch 语句会失败? ?如果我将 Oscar 声明为常量,我可以理解错误:
const oscar = 'dog';
,因为在那种情况下,它永远是一只狗,没有别的。然而,试想一下,如果巫师施展某种咒语,奥斯卡可能会变成一只猫:let oscar: Animal = 'dog';
while(true) {
switch (oscar) {
case 'bird':
...
case 'cat':
...
case 'dog':
console.log('bark');
// here comes the wizard
if(wizard.performsSpell('makeOscarBecomeACat')) {
oscar = 'cat'; // that should be valid, because oscar is of type Animal
}
break;
}
}
我对变量
oscar
的赋值有什么误解吗? ,或者这只是一个 TypeScript 错误?
最佳答案
您可能会误解的是 TypeScript 2.0 及更高版本有一个名为 control-flow based type analysis 的功能。 ,在 microsoft/TypeScript#8010 中实现.此功能的效果之一是
An assignment (including an initializer in a declaration) of a value of type
S
to a variable of typeT
changes the type of that variable toT
narrowed byS
in the code path that follows the assignment. [...] The typeT
narrowed byS
is computed as follows: [...] IfT
is a union type, the result is the union of each constituent type inT
to whichS
is assignable.
这意味着声明
let oscar: Animal = 'dog';
被解释为:“变量
oscar
的类型为 Animal
,一个联合类型。它被分配了一个字符串字面量类型 "dog"
的值,所以在它被重新分配之前,我们将处理变量 oscar
因为类型 Animal
缩小了 "dog"
,也就是 "dog"
。因此在您的
switch
/case
陈述:case 'bird': // error!
// ~~~~~~ <-- Type '"bird"' is not comparable to type '"dog"'
您收到关于尝试比较字符串文字的错误
"bird"
到字符串文字 "dog"
.编译器知道 'bird'
case 是不可能的,因为你没有重新分配 oscar
与 'bird'
兼容的东西.即使在您的
wizard
在这种情况下,编译器知道当它到达 switch
/case
声明,oscar
只能是 "cat"
或 "dog"
而不是 "bird"
:case 'bird': // error!
// ~~~~~~ <-- Type '"bird"' is not comparable to type '"cat" | "dog"'
这可能都是好消息;编译器正在捕获永远不会发生的情况。在许多情况下,这些都是真正的错误。
如果您不希望编译器意识到
oscar
绝对是"dog"
只知道这是一个Animal
(例如,一个占位符,直到您编写的代码真正有可能成为 Animal
的任何成员),您可以使用 type assertion在作业本身:let oscar: Animal = 'dog' as Animal;
现在您的所有其他代码都将编译而不会出错。您甚至可以忘记注释,因为它对您没有帮助:
let oscar = 'dog' as Animal;
好的,希望有帮助;祝你好运!
Playground link to code
关于javascript - 联合类型的变量导致 switch 语句中的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59988669/