我正在处理一个数组,如果数组的长度为 1,则第一个元素的类型是已知的,并且可以是两种类型之一,否则;即类似以下内容:
type NarrowableArray<TKnown, TGenereal> = [TKnown] | [TGeneral, TGeneral, ...TGeneral[]]
type Foo = number | number[]
let a: NarrowableArray<number, Foo> = Math.random() > 0.5 ? [3] : [3,4,5]
if (a.length === 1) {
a
console.log(a[0] + 2) //Error > TS can't tell `a[0]` has type 'number'.
}
这是预期的吗? 有没有办法让函数声明中的类型缩小工作相同?
开放式元组类型
的
length
属性是number
,如microsoft/TypeScript#24897中所述; TypeScript 没有准确的 range types(如 microsoft/TypeScript#15480 中所要求的)来表达“除
1
之外的任何数字”或
{length: WholeNumber & GreaterThan<1>}
。所以不幸的是,仅仅检查
length
的
1
属性将无法区分union,因为两个union成员都有一个
length
,
1
可分配给它。还有其他更自然地直接与元组一起工作的缩小方法,但是如果您想自己执行长度检查,您可能需要重构为
用户定义的类型保护函数,形式为:
function hasLengthOne(x: any[]): x is [any] {
return x.length === 1;
}
然后调用它而不是直接检查长度:
function aFunction(a: NarrowableArray<number, Foo>) {
if (hasLengthOne(a)) {
a // (parameter) a: [number]
console.log(a[0] + 2); // okay
} else {
a // (parameter) a: [Foo, Foo, ...Foo[]]
}
}
之所以有效,是因为编译器能够通过 NarrowableArray<number, Foo>
过滤
[any]
;我们正在完全规避
length
问题。