网站搜索

如何为数组到对象的一对一转换编写 TypeScript 泛型类型


目标

我想为数组到对象的一对一转换写一个 TypeScript 泛型类型,这个函数像

transArrayToObject([
  [1, 'A'],
  [2, 'B'],
] as const)

// type output
{
  readonly A: 1;
  readonly B: 2;
}

我已经尝试过

type Data = readonly (readonly [number, string])[]

type TransArrayToObject = <TD extends Data>(
  data: TD,
) => {
  readonly [K in TD[number][1]]: TD[number][0]
}

// Code details are omitted
const transArrayToObject = (() => ({})) as TransArrayToObject

transArrayToObject([
  [1, 'A'],
  [2, 'B'],
] as const)

但是类型结果是:

{
  readonly A: 1 | 2;
  readonly B: 1 | 2;
}

这不是我想要的。我不知道如何写‘A’对应1,‘B’对应2,

答案#1

考虑这个例子:

const Tpl = [
  [1, 'A'],
  [2, 'B'],
] as const

type Tpl = typeof Tpl


type Transform<
  Tuple extends readonly any[],
  Result extends Readonly<Record<string, any>> = {}> =
  (Tuple extends []
    ? Result // last call
    : Tuple extends readonly [infer Head, ... infer Tail]
    ? (Head extends readonly [infer Value, infer Key]
      ? (Key extends PropertyKey
        ? Transform<Tail, Result & Readonly<Record<Key, Value>>>
        : never)
      : never)
    : never)

type Result = Transform<Tpl>

操场

Transform - 遍历 Tpl 并推断每个元素。如果元素是带有键/值对的元组,则创建一个 Record<Key,Value>,将其分配给 Result 并再次递归调用 Transform

如果你对元组操作感兴趣,请查看我的博客