首页 > 解决方案 > 为什么在这种情况下不能从参数推断出通用值 N?

问题描述

这个问题:

TypeScript:要求两个数组的长度相同?

询问如何创建一个需要两个长度相同的数组的函数。

这是我的解决方案尝试。

type ArrayOfFixedLength<T extends any, N extends number> = readonly T[] & { length: N }; 

const a1: ArrayOfFixedLength<number, 2> = [1] as const; //expected error
const a2: ArrayOfFixedLength<number, 2> = [1, 2] as const; 


function myFunction<N extends number>(array1: ArrayOfFixedLength<any, N >, array2: ArrayOfFixedLength<any, N>) {
return true; 
}

myFunction<3>([1, 2, 3] as const, [2, 3, 4] as const); 
myFunction<2>([1, 2] as const, [1, 2, 3] as const); //expected error

// However, if you don't specify the array length, 
// It fails to error
myFunction([1, 2, 3] as const, [2, 3, 4] as const); 
myFunction([1, 2] as const, [1, 2, 3] as const); // error is expected, but there is none. 

操场

如前所述,如果您明确声明通用值N- 数组的长度,此代码只会给出 TypeScript 错误。

为什么 TypeScript 无法从传递给函数的参数中推断出值 N?

标签: typescriptgenerics

解决方案


您需要向编译器提示以期望元组类型。否则,编译器将扩​​展数组文字[2, 3, 4],如number[]. 提示通常采用在类型注释或泛型约束中包含元组类型的形式;最好是某种元组类型的联合,它不会妨碍你正在做的事情:

function myFunction<N extends number>(
    array1: ArrayOfFixedLength<any, N> | [never],
    array2: ArrayOfFixedLength<any, N & {}> | [never]) {
    return true;
}

| [never]一个提示。有关更多信息,请参阅microsoft/TypeScript#27179,特别是此评论。我之所以使用[never]是因为我希望您不会传递任何带有never值的数组,因此在实践中是否array1接受这样的数组并不重要。

是的,它很丑。我在microsoft/TypeScript#30680中要求提供一种更简单的方法,但我不知道是否会实施类似的方法。


另外,请注意,array2我已经替换NN & {}. 如果您不这样做,您的函数将无法将两个数组限制为相同的长度;相反,N只会被推断为两个数组长度的并集。理想情况下,您只想用于 array1推断 N并且Ninarray2应该是“非推断的”。有一个开放的 GitHub 问题microsoft/TypeScript#14829,要求对此提供支持。这& {}是一种降低推理优先级N的技术,它仅用于推断和array1不推断就足够了array2

让我们看看它的工作原理:

myFunction([1, 2, 3] as const, [2, 3, 4] as const); // okay
myFunction([1, 2] as const, [1, 2, 3] as const); // error
myFunction([1, 2, 3], [2, 3, 4]); // okay
myFunction([1, 2], [1, 2, 3]); // error

对我来说看上去很好。好的,希望有帮助;祝你好运!

Playground 代码链接


推荐阅读