【问题标题】:Why is the generic value N not inferred from arguments in this case?为什么在这种情况下不能从参数推断出通用值 N?
【发布时间】:2020-06-12 20:01:10
【问题描述】:

这个问题:

TypeScript: Require that two arrays be the same length?

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

这是我的解决方案尝试。

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

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

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

【问题讨论】:

    标签: typescript generics


    【解决方案1】:

    你需要给编译器一个提示以期望一个元组类型。否则编译器会将像[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,特别是 this comment。我使用了[never],因为我希望您不会传递任何具有never 值的数组,因此在实践中array1 是否接受这样的数组并不重要。

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


    另外,请注意,对于array2,我已将N 替换为N &amp; {}。如果您不这样做,您的函数将无法将两个数组限制为相同的长度;相反,N 将被推断为两个数组长度的并集。理想情况下,您希望only array1 用于推断 N,并且array2 中的N 应该是“非推断性的”。有一个开放的 GitHub 问题,microsoft/TypeScript#14829,要求对此提供支持。 &amp; {} 是一个technique to lower the inference priority,它仅能从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
    

    我觉得不错。好的,希望有帮助;祝你好运!

    Playground link to code

    【讨论】:

    • 呃。我越来越意识到,虽然 typescript 可能可以做任何你想做的事情,但要做到这一点很难。
    猜你喜欢
    • 2017-05-20
    • 1970-01-01
    • 2011-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多