Typescript 如何从对象的元组创建对象类型?
从该数据结构中:Typescript 如何从对象的元组创建对象类型?,typescript,tuples,mapped-types,Typescript,Tuples,Mapped Types,从该数据结构中: const属性=[ {name:'name',类型:'}, {name:'age',类型:0}, {name:'sex',键入:['m','f']as const}, {name:'username',类型:''} ] 我正在尝试动态构造以下类型: type Person={ 名称:字符串; 年龄:人数; 性别:'m'|'f'; 用户名:字符串; } 我知道TypeScript可以通过映射其他类型来创建类型。但是这里的源对象是一个数组,所以看起来有点棘手。我该怎么做呢?这其
const属性=[
{name:'name',类型:'},
{name:'age',类型:0},
{name:'sex',键入:['m','f']as const},
{name:'username',类型:''}
]
我正在尝试动态构造以下类型:
type Person={
名称:字符串;
年龄:人数;
性别:'m'|'f';
用户名:字符串;
}
我知道TypeScript可以通过映射其他类型来创建类型。但是这里的源对象是一个数组,所以看起来有点棘手。我该怎么做呢?这其实没那么难。您所需要的只是一个映射类型,其中的键被重新映射到元组成员的
name
属性的类型(这可以很好地实现)以及相应成员的type
属性的值
首先,您需要让编译器知道属性
数组实际上是一个元组,具有as const
断言:
const属性=[
{name:'name',类型:'},
{name:'age',类型:0},
{name:'sex',键入:['m','f']as const},
{name:'username',类型:''}
]作为常量;
接下来,让我们定义一个能够对元组成员的任意属性进行操作的泛型类型,从而使该类型可重用。首先,我们需要提取能够映射的索引
成员以一对一的方式访问属性。这是通过排除(仅保留索引)完成的
我们可以使用生成的索引并集进行映射:
类型TupleToProps={
[P作为T[P][VP]和字符串排除在外]:T[P][VV]
};
VP
和VV
确保实用程序类型可以处理任何同质的对象元组,并且&string
只保留与字符串兼容的属性。这已经给我们带来了一个非常好的结果:
type PersonTest=TupleToProps;
/**
*类型PersonTest={
*姓名:”;
*年龄:0岁;
*性别:只读[“m”,“f”];
*用户名:“”;
* }
*/
在此之后,这只是一个表面上的变化:从类似元组的类型中提取值并扩大文本类型(由和Q&a提供,并进行了一个小的升级,以排除不应扩大的键):
键入ToPrimitive=
T扩展字符串?一串
:T扩展数字?数
:T扩展布尔值?布尔值
:T;
//将保留具有更宽值类型的键的映射类型
类型加宽={
[K in keyof O]:K扩展E?O[K]:ToPrimitive
}
类型TupleToPropsTwo=加宽;
类型PersonTest2=TupleToPropsTwo;
/**
*类型PersonTest2={
*名称:字符串;
*年龄:人数;
*性别:“m”|“f”;
*用户名:字符串;
* }
*/
映射类型确实是一条可行之路。为确保没有类型被加宽,您必须将作为常量添加到属性中
:
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]>
}
要获取名称,可以使用简单的条件类型:
type Name<O> = O extends { name: infer N } ? N extends string ? N : never : never
extends子句用于防止推断太窄的类型(例如,'
而不是string
),并用于推断数组的联合类型。如果需要,可以添加更多类型
有了这些定义,属性
可以用
type Person = FromProperties<typeof properties>
// Inferred type:
// type Person = {
// name: string;
// age: number;
// sex: "m" | "f";
// username: string;
// }
type Person=FromProperties
//推断类型:
//类型人={
//名称:字符串;
//年龄:人数;
//性别:“m”|“f”;
//用户名:字符串;
// }
我认为您必须编写一个脚本,将属性
数组转换为类型声明,并将其放入.d.ts文件中。
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
type Person = FromProperties<typeof properties>
// Inferred type:
// type Person = {
// name: string;
// age: number;
// sex: "m" | "f";
// username: string;
// }