从这个数据结构:
const properties = [
{ name: 'name', type: '' },
{ name: 'age', type: 0 },
{ name: 'sex', type: ['m', 'f'] as const },
{ name: 'username', type: '' }
]
我正在尝试动态构建以下类型:type Person = {
name: string;
age: number;
sex: 'm'|'f';
username: string;
}
我知道 TypeScript 可以通过映射其他类型来创建类型。但是这里的源对象是一个数组,所以看起来有点棘手。我该怎么做?
最佳答案
映射类型确实是要走的路。为确保没有类型被加宽,您必须添加 as const
至 properties
:
const properties = [
{ name: 'name', type: '' },
{ name: 'age', type: 0 },
{ name: 'sex', type: ['m', 'f'] as const },
{ name: 'username', type: '' }
] as const
然后,您可以使用映射类型,在该类型中将键从数组索引重新映射到属性名称并将值映射到类型。映射类型本身如下所示:type FromProperties<P extends readonly unknown[]> = {
[K in IndexKeys<P> as Name<P[K]>]: Type<P[K]>
}
它映射实际索引的键( '0'
、 '1'
等)而不是数组属性,将键重新映射到属性 name
,并有 Type<P[K]>
作为值(value)。要获得正确的索引键,您可以排除
[]
上的属性。从你的数组中,所以只剩下索引:type IndexKeys<A extends readonly unknown[]> = Exclude<keyof A, keyof []>
要获取名称,可以使用一个简单的条件类型:type Name<O> = O extends { name: infer N } ? N extends string ? N : never : never
并确定每个type
的实际类型值,您可以使用稍微复杂的条件类型:type Type<O> =
O extends { type: infer T }
? T extends number ? number
: T extends string ? string
: T extends readonly unknown[] ? T[number]
: never // `name` property is not a number, string or array
: never // object has no `type` property
extends 子句是为了防止推断太窄的类型(例如 ''
而不是 string
)并推断数组的联合类型。如果需要,您可以添加更多类型。有了这些定义,
Properties
可以用type Person = FromProperties<typeof properties>
// Inferred type:
// type Person = {
// name: string;
// age: number;
// sex: "m" | "f";
// username: string;
// }
TypeScript playground
关于typescript - 如何从对象元组创建对象类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66500731/