从数组字面量推断类型
我有一个函数,它接受一个数组,并返回一个对象,该对象的键是使用数组中的值设置的。
简化示例:
// arr will be an array of arrays of type [string] *or* [string, string]
function foo(arr) {
const output = {}
arr.forEach(value => {
// if this value has length 2, use the second string as the key
const key = value.length === 1 ? value[0] : value[1]
// always use the first string as the value
const value = value[0]
output[key] = value
})
return output
}
例如,运行foo([['a', 'orange'], ['b'], ['c', 'apple'])将产生{ orange: 'a', b: 'b', apple: 'c' }类型{ orange: string, b: string, apple: string }- 让我们称之为类型R- 请注意,我并不真正关心R文字的值。这将是一个不错的奖励,但更通用的string类型就足够了。
随着打字稿我想推断的返回类型foo,R从一个普通的输入arr,T。
我可以输入T像这样
function foo<T extends Array<[string, string?]>(arr: T) { ... }
它是那么可以推断R从T?
更新
我可以看到的一个潜在问题是,与 Typescript 的功能限制相悖,R需要关心 的值的顺序,T因为您当然可以指定重复的键。
即它不像类似的泛型对象类型 -> 泛型对象类型映射语法那样纯粹[K in keyof T]: T[K] extends Thing ? ... : ...。
如果这是一个问题,但有可能绕过它并简单地忽略它,即仅在没有任何重复键的情况下使这种类型安全,那么这对我的用例来说很好。
回答
这是可行的:
type Values<T> = T[keyof T];
type Tuple<K, V = 1> = [K, V?]
type Elem = Tuple<any, any>
/**
* Infers all elements in tuple and converts it
* to object
*/
type Predicate<T> =
T extends Tuple<infer K, infer V>
? V extends PropertyKey
? Record<V, K>
: K extends PropertyKey
? Record<K, K>
: never
: never
/**
* Iterate through argument
*/
type Reducer<
Arr extends ReadonlyArray<Tuple<any, any>>,
Result extends Record<string, any> = {}
> = Arr extends []
// last step of iteration
? Result
// if there are still tuples in the array
: Arr extends readonly [infer H, ...infer Tail]
? Tail extends ReadonlyArray<Tuple<any, any>>
? H extends Elem
// call utility type recursively and produce record type with help of predicate
? Reducer<Tail, Result & Predicate<H>>
: never
: never
: never
// we need to infer each key and property, thats why I used extra K,V generics
declare function foo<K extends string, V extends string, Tuples extends Tuple<K, V>[]>(tuples: [...Tuples]): Reducer<[...Tuples]>
foo([['a', 'orange'], ['b'], ['c', 'apple']]) // Record<"orange", "a"> & Record<"b", "b"> & Record<"apple", "c">
操场
const在这种情况下不需要使用断言
您可以在我的博客中找到更多示例
在这里您可以找到如何从函数参数推断其他数据结构