typescript 如何将泛型数组转换为记录,同时保留每个索引的文字类型?

pn9klfpd  于 2023-06-24  发布在  TypeScript
关注(0)|答案(1)|浏览(132)

假定

type Person = {
  name: string;
  age: number;
};

const bob = {
  name: "Bob",
  age: 32,
} as const;

const alice = {
  name: "Alice",
  age: 43,
} as const;

我想写一个函数,它接受一个Person并将其转换为一个对象,其中键是Persons的名称,值是Person对象。
如果我想和一个人做这个我可以做

function getPerson<T extends Person>(personOption: T) {
  let person = {} as Record<(typeof personOption)["name"], typeof personOption>;
  return person;
}

const person = getPerson(bob); // Bob: {name: "Bob", age: 32}
const personName = person.Bob.name; // Bob

但是,如果我想扩展这个功能以容纳一个数组的人,那么文字类型不会转换成它们各自的索引

function getPeople<T extends Person>(peopleOptions: T[]) {
  let people = {} as Record<
    (typeof peopleOptions)[number]["name"],
    (typeof peopleOptions)[number]
  >;
  return people;
}

const people = getPeople([bob, alice]);

const bobName = people.Bob.name; // Bob | Alice
const aliceName = people.Alice.name; // Bob | Alice

我如何重写它,使bobName返回“Bob”,aliceName返回“Alice”,而不是两者的并集?

nbnkbykc

nbnkbykc1#

首先,我们将使用下面的实用程序类型来使IDE中显示的类型更具可读性(没有&):

type Prettify<T> = T extends infer R ? {
  [K in keyof R]: R[K]
} : never

对于实际的实现,我们将使用mapped types遍历数组和键重Map来创建对象,其中键是数组元素的名称:

type MapPeople<T extends readonly Person[]> = Prettify<{
  [K in T[number] as K['name']]: K
}>

用途:

function getPeople<T extends readonly Person[]>(peopleOptions: T) {
  let people = {} as MapPeople<T>;
  return people;
}

测试:

// const people: {
//     Bob: {
//         readonly name: "Bob";
//         readonly age: 32;
//     };
//     Alice: {
//         readonly name: "Alice";
//         readonly age: 43;
//     };
// }
const people = getPeople([bob, alice]);

const bobName = people.Bob.name; // Bob
const aliceName = people.Alice.name; // Alice

链接到Playground

相关问题