为什么在这种情况下不能从参数中推导出泛型值N? [英] Why is the generic value N not inferred from arguments in this case?

查看:74
本文介绍了为什么在这种情况下不能从参数中推导出泛型值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. 

解决方案

您需要给编译器一个提示,以期望使用元组类型.否则,编译器会将像[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 ,尤其是 microsoft/TypeScript#30680 中找到一种更简单的方法,但我不知道不知道这样的事情是否会付诸实施.


此外,请注意,对于array2,我已将N替换为N & {}.如果不这样做,则函数将无法将两个数组限制为相同的长度.而是将N推断为两个数组的长度的并集.理想情况下,您只希望 array1用于推断 N,并且array2中的N应该是非推断"的.有一个公开的GitHub问题, microsoft/TypeScript#14829 ,要求支持这一点. & {}降低推理优先级的技术,足以仅从array1推断N而不是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

对我很好.好吧,希望能有所帮助;祝你好运!

游乐场连结代码

This question:

TypeScript: Require that two arrays be the same length?

Asks how to create a function that requires two arrays of the same length.

Here's my attempt at a solution.

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. 

Playground

As noted, this code only gives the TypeScript error if you explicitly state the generic value N - the length of the arrray.

Why is TypeScript unable to infer the value N from the arguments passed into the function?

解决方案

You need to give a hint to the compiler to expect a tuple type. Otherwise the compiler will widen an array literal like [2, 3, 4] to number[]. The hint usually takes the form of including a tuple type in the type annotation or generic constraint; preferably a union of some tuple type that doesn't get in the way of what you're doing:

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

The | [never] is a hint. See microsoft/TypeScript#27179 and specifically this comment for more information. I used [never] since I expect that you won't pass any arrays with a never value, so it won't matter in practice if array1 accepts such an array.

Yes, it's ugly. I've asked for an easier way in microsoft/TypeScript#30680, but I don't know if something like that will ever be implemented.


Also, note that for array2 I've replaced N with N & {}. If you don't do that, your function will not serve the purpose of constraining the two arrays to the same length; instead, N will just be inferred as the union of the lengths of the two arrays. Ideally you want only array1 to be used to infer N, and the N in array2 should be "non-inferential". There's an open GitHub issue, microsoft/TypeScript#14829, asking for support for this. The & {} is a technique to lower the inference priority, which suffices to only infer N from array1 and not array2.

Let's see it work:

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

Looks good to me. Okay, hope that helps; good luck!

Playground link to code

这篇关于为什么在这种情况下不能从参数中推导出泛型值N?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆