考虑到我们有一个表示三种不同字符串值之一的并集类型。
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)
(带cat的模拟)。但是,如果我对变量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中实现。此功能的作用之一是
在代码中将类型为
S
的值的赋值(包括声明中的初始化程序)分配给类型为T
的变量,将该变量的类型更改为T
并由S
缩小]分配后的路径。 [...]类型T
缩小了S
的计算如下:[...]如果T
是联合类型,则结果是T
中每个组成类型的联合],S
可分配给它。
这意味着声明
let oscar: Animal = 'dog';
解释为:“变量oscar
具有类型Animal
,是联合类型。它已被分配了字符串文字类型"dog"
的值,因此,在重新分配变量之前,我们将对待变量[ C0]作为类型oscar
缩小Animal
,即"dog"
。
因此在您的"dog"
/ switch
语句中:
case
[有关尝试将字符串文字case 'bird': // error!
// ~~~~~~ <-- Type '"bird"' is not comparable to type '"dog"'
与字符串文字"bird"
比较的错误。编译器知道"dog"
情况是不可能的,因为尚未将'bird'
分配给与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;