输入泛型推断类型数组

Jer*_*eng 4 generics nested inference type-inference typescript

我正在尝试创建对象数组的类型。该对象的第一个和第二个键需要匹配。例如:

[{ 
  key1: "hi",
  key2: "world"
},{
  key1: 1,
  key2: 2
},{
  key1: true,
  key2: false
}]
Run Code Online (Sandbox Code Playgroud)

这是我想出来的,但它并不完全有效。我有一个通用类型来定义数组中的对象。当调用它生成数组类型时,会引发错误。

type ArrayItem<T> = {
  key1: T,
  key2: T
}

// This raises an error Generic Type ArrayItem requires 1 type argument
type Array = ArrayItem<T>[]
Run Code Online (Sandbox Code Playgroud)

输入这样的嵌套对象(具有类型推断支持)的最佳方法是什么?

jca*_*alz 5

如果您没有Tin可能类型的有限列表ArrayItem<T>,则 TypeScript 中没有与 对应的具体类型Array<ArrayItem<T>>。要将此类事物表示为非泛型类型,需要诸如存在类型之类的东西,而 TypeScript 并不直接支持这种类型。

(如果您确实有一个有限列表,例如ArrayItem<string> | ArrayItem<number> | ArrayItem<boolean>,那么您可以像其他答案一样使用并集。)

在 TypeScript 中最接近的就是作为泛型类型,而在推理和编译器警告方面最好的做法是将其表示为类似泛型约束的东西。

一种方法是编写一个asMyArray()接受tuple 的通用辅助函数,编译器将检查 tuple 的每个元素以确保它满足约束。一个障碍是,如果您允许诸如as之类的事情,则{key1: "hi", key2: 2} 确实满足约束。为了防止编译器愉快地接受所有类型对,我将尝试使其仅从推断(请参阅microsoft/TypeScript#14829以了解防止从特定推断站点推断的方法),然后仅检查string | numberTTkey1key2匹配:

type NoInfer<T> = [T][T extends any ? 0 : 1]

const asMyArray = <T extends readonly any[]>(
    x: [...({ [K in keyof T]: { key1: T[K], key2: NoInfer<T[K]> } })]) =>
    x;
Run Code Online (Sandbox Code Playgroud)

泛型类型参数是与传入数组的每个元素的值T相对应的元组。key1传入的数组x映射元组类型。该& {}位降低了 的推理优先级key2。该[... ]位只是提示编译器推断一个元组而不是一个数组(它无法区分不同的元素),让我们测试一下:

const myArray = asMyArray([{
    key1: "hi",
    key2: "world"
}, {
    key1: 1,
    key2: 2
}, {
    key1: true,
    key2: false
}])
// const asMyArray: <[string, number, boolean]>(...)
Run Code Online (Sandbox Code Playgroud)

你可以看到它T被推断为[string, number, boolean]。这是成功的,而以下以T相同方式推断的失败:

const badArray = asMyArray([{
    key1: "hi", key2: 123 // error!
    // -------> ~~~~
    // number not assignable to string
}, {
    key1: 1, key2: "world" // error!
    // ----> ~~~~
    // string not assignable to number
}, {
    key1: true, key2: false
}]);
Run Code Online (Sandbox Code Playgroud)

看起来像你想要的。好的,希望有帮助;祝你好运!

Playground 代码链接