如何在 Typescript 中使用另一个对象的值派生对象类型?

How to derive an object type with another object's values in Typescript?

我正在尝试创建一个函数,该函数将 return 具有从传入该函数的参数派生的键的通用对象类型。一个简化的例子:

// What do I put here for this to work?
type ObjectB<T> = {};

declare function makeObjectB<T>(a: T): ObjectB<T>;

const objectB = makeObjectB({
  name: "foo"
});

console.log(objectB.foo)

typeof objectB 会导致类似:

{
  foo: string
}

如果还支持以下示例,则加分:

// What do I put here for this to work?
type ObjectB<T> = {};

declare function makeObjectB<T>(a: T[]): ObjectB<T[]>;

const objectB = makeObjectB([{ name: "foo" }, { name: "bar" }]);

console.log(objectB.foo)
console.log(objectB.bar)

typeof objectB => { foo: string; bar: string }

当然是,映射类型:

type ObjectB<T extends { name: string }> = {
    [K in T["name"]]: string;
};

您会注意到 T 之后的 extends { name: string }。这是一个通用约束,与函数参数类型参数相似

在映射类型中,我们遍历 T["name"] 中的每个 K 并将其映射到 string.

所以如果我们有这个:ObjectB<{ name: "foo" }>T["name"] 将是 "foo" 并且这种类型将导致:

{
    foo: string;
}

有了这个类型,我们现在可以写我们的函数签名了:

declare function makeObjectB<T extends { name: string }>(a: T): ObjectB<T>;

您还会注意到此处存在相同的通用约束。这是为了满足 makeObjectB 中的 T 可以与 ObjectB.

一起使用的 TypeScript

对于奖励积分,我们可以定义一个重载:

declare function makeObjectB<T extends ReadonlyArray<{ name: string }>>(a: T): ObjectB<T[number]>;

T 现在可以是具有指向字符串的 name 键的任何对象数组。

另一个不同之处在于使用 ObjectB<T[number]> 而不是 ObjectB<T>。这让我们可以将数组中的所有元素(这里从技术上讲是元组)作为联合,这意味着 T["name"] 现在类似于 "foo" | "bar".

您可以试试这个解决方案 here