TypeScript检查变量是否是元组或元组的数组



给出以下代码仅供示例使用:

type tuple = [key: string, value: number];
function foo(arg: tuple | Array<tuple>) {
const arr = Array.isArray(arg[0]) ? arg : [arg];
// The type of arr is: tuple | (tuple | tuple[])[]
console.log(arr.length);
}
foo(['key', 111]);
foo([['key', 222]]);

我也尝试过typeof arg[0] === 'string' ? [arg] : arg,但这也导致了同样的结果。运行代码会得到预期的结果,arr总是一个元组数组,但是TypeScript并不"知道"。它。

如何使typescript正确地将arr的类型缩小为tuple[]而不显式地断言它?

编译器只看到您将arg[arg]分配给arr。它不改变认为arg的类型是基于Array.isArray(arg[0])的,所以arr的类型是arg[arg]类型的并集。arg的类型是tuple | tuple[],所以[arg]的类型是(tuple | tuple[])[];这些类型的并集简化为tuple | (tuple | tuple[])[],因为tuple[](tuple | tuple[])[]的子集。

您可以将Array.isArray包装在用户定义的类型保护中,以使编译器按照您想要的方式解释内容。

function isArrayOfTuples(arg: tuple | tuple[]): arg is tuple[] {
return Array.isArray(arg[0]);
}
function foo(arg: tuple | tuple[]) {
const arr: tuple[] = isArrayOfTuples(arg) ? arg : [arg];
console.log(arr.length);
}

否则,我认为您必须明确断言类型才能做到这一点。

const arr: tuple[] = Array.isArray(arg[0]) ? arg as tuple[] : [arg] as tuple[];

另一个可能更容易实现的选项是将arg的类型更改为tuple[]。想要传递单个tuple的调用者可以将参数包装在数组中。