假设你有一些东西可以是数字或字符串数组,你想要映射到这个数组。使用打字稿,表达这种情况的以下方式都可以被类型检查器接受。
[1, 2].map(e => console.log(e));
let arr: string[] | number[] = [1, 2];
arr.map(e => console.log(e));
但是如果我们添加一个显式的静态类型转换,为了描述arr,编译器将以我们的方式抛出错误:
(arr as string[] | number[]).map(e => console.log(e));
// Cannot invoke an expression whose type lacks a call signature.
// Type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => U[]) | (...' has no compatible call signatures.
你知道为什么会这样,或者这可能是编译器本身的问题吗?
答案 0 :(得分:2)
在第一种情况下,您实际上看到了流量控制分析的实际应用。由于您只为变量分配了一个数字数组,编译器将确定arr
的实际类型为number[]
,并且它将与之一起运行,使map
调用有效。如果您实际为变量分配了string[]
,并且编译器无法静态地决定实际采用哪个代码路径,那么您将收到与显式强制转换相同的错误:
declare var decider : boolean
let arr: string[] | number[] = decider ? [1, 2] : ['a', 'b'];
arr.map(e => console.log(e)); // Will be an error
至于为什么map
在string[] | number[]
的并集上不可调用,原因是map
的类型将是来自{{1}的两个可用签名的联合类型}和string[]
签名不相同,它们之间不会发生合并。由于两个签名的并集不可调用,因此您将收到错误。