从数组字面量推断类型

我有一个函数,它接受一个数组,并返回一个对象,该对象的键是使用数组中的值设置的。

简化示例:

// 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类型就足够了。

随着打字稿我想推断的返回类型fooR从一个普通的输入arrT

我可以输入T像这样

function foo<T extends Array<[string, string?]>(arr: T) { ... }

它是那么可以推断RT


更新

我可以看到的一个潜在问题是,与 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在这种情况下不需要使用断言

您可以在我的博客中找到更多示例

在这里您可以找到如何从函数参数推断其他数据结构


以上是从数组字面量推断类型的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>