如何在 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。
我正在尝试创建一个函数,该函数将 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
.
对于奖励积分,我们可以定义一个重载:
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。