如果在ArrayItem<T> 中没有T 的可能类型的有限列表,则TypeScript 中没有与Array<ArrayItem<T>> 对应的具体类型。要将这样的东西表示为非泛型类型需要像 existential types 这样的东西,TypeScript 并不直接支持。
(如果您确实有一个有限列表,例如ArrayItem<string> | ArrayItem<number> | ArrayItem<boolean>,那么您可以像其他答案一样使用联合。)
在 TypeScript 中最接近这一点的是泛型类型,在推理和编译器警告方面,最好的做法是将其表示为 generic constraint 之类的东西。
一种方法是编写一个通用帮助函数asMyArray() 接受tuple,编译器将检查元组的每个元素以确保它满足约束条件。一个障碍是{key1: "hi", key2: 2} 确实 满足约束条件,如果你允许像string | number 这样的东西作为T。为了防止编译器愉快地接受所有类型对,我将尝试使其仅从key1 推断T(请参阅microsoft/TypeScript#14829 以查看防止从特定推断站点推断的方法),然后检查key2 匹配:
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;
泛型类型参数T 是一个元组,对应于传入数组的每个元素的key1 值。传入的数组x 属于mapped tuple type。 & {} 位降低了key2 的推理优先级。 [... ] 位只是提示编译器推断一个元组而不是一个数组(它无法区分不同的元素),让我们测试一下:
const myArray = asMyArray([{
key1: "hi",
key2: "world"
}, {
key1: 1,
key2: 2
}, {
key1: true,
key2: false
}])
// const asMyArray: <[string, number, boolean]>(...)
你可以看到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
}]);
看起来像你想要的。好的,希望有帮助;祝你好运!
Playground link to code