如何用TypeScript语法糖生成属性名与值相同的对象?
实现属性名与值一致的TypeScript对象约束
问题描述
需要创建一个属性名与属性值完全相同的对象,且对象属性必须匹配自定义类型MyType的所有属性。目前通过{ [key in keyof MyType]: string }能约束对象包含所有属性,但无法限制属性值必须和属性名一致,同时想找到类似Object.keys(MyType)的简化写法(注:MyType是类型而非对象,此写法无效)。
相关代码示例:
type MyType = { propA: string; propB: string; propC: string; } // 目标对象 const foo = { propA: "propA", propB: "propB", propC: "propC", }
当前仅能约束属性存在的写法:
const foo: { [key in keyof MyType]: string } = { propA: "propA", propB: "propB", propC: "propC", };
期望的简化示意写法(实际无效):
const foo: { [key in keyof MyType]: string } = Object.keys(MyType);
解决方案
1. 强化类型约束:确保值与属性名一致
修改类型定义,将属性值的类型从string改为属性名的字面量类型K,让TypeScript强制要求属性值必须等于属性名:
type MyType = { propA: string; propB: string; propC: string; }; // 新的类型约束:值必须等于属性名字面量 type KeyValMatching<T> = { [K in keyof T]: K }; // 此时如果值和属性名不匹配,TS会直接报错 const foo: KeyValMatching<MyType> = { propA: "propA", // 符合要求 propB: "propX", // 错误:"propX"无法赋值给类型"propB" propC: "propC", // 符合要求 };
2. 简化对象创建:避免手动重复编写键值
由于TypeScript类型仅存在于编译阶段,无法直接从MyType生成运行时对象,但可以通过两种方式简化编写:
方式一:先定义运行时对象,再推导类型
这是最简洁的方式,完全避免重复编写键值和类型:
// 创建符合要求的运行时对象,用as const锁定字面量类型 const fooRaw = { propA: "propA", propB: "propB", propC: "propC", } as const; // 从运行时对象自动推导MyType类型 type MyType = typeof fooRaw; // 直接使用该对象,类型完全匹配 const foo: MyType = fooRaw;
方式二:工具函数生成键值一致的对象
如果必须先定义MyType类型,可以写一个工具函数自动生成目标对象:
type MyType = { propA: string; propB: string; propC: string; }; // 工具函数:接收键数组,返回键值一致的对象 function createKeyValObj<T extends string>(keys: T[]): { [K in T]: K } { return keys.reduce((obj, key) => { obj[key] = key; return obj; }, {} as { [K in T]: K }); } // 生成对象:通过{} as MyType让TS推导键数组,再断言为keyof MyType[] const foo: { [K in keyof MyType]: K } = createKeyValObj( Object.keys({} as MyType) as (keyof MyType)[] );
这种方式下,只要MyType的属性发生变化,只需修改类型定义,工具函数会自动生成对应的键值一致对象。
内容的提问来源于stack exchange,提问作者Hans Araya
相关产品推荐
相关产品推荐

