如何从TypeScript序列化规范数组推断字段名联合类型?
TypeScript从对象列表自动推断字段名联合类型及值类型映射
问题场景
我正在编写TypeScript代码,用对象字面量列表定义序列化格式规范,希望从列表中name键的固定值自动推断出联合类型,用于验证其他地方的键是否正确。示例代码如下:
const spec = [ { //1 name: "Field 1", start: 1, width: 4, padding_position: "end", }, { //2 name: "Field 2", type: "int", start: 5, width: 5, padding_symbol: "0", }, { //3 name: "Field 3", start: 10, width: 20, padding_position: "end", }, { name: "Field 4", start: 30, width: 2, padding_position: "end", }, ];
期望实现:
type FieldName = /* insert inference magic here */ const dataToSerialize: { [K in FieldName]?: string | number } = { "Field 1": "value" };
核心需求是遵循DRY原则,避免手动重复定义FieldName联合类型;额外需求是能根据对象中的可选type键,自动映射对应的值类型,替代string | number。
核心需求实现:自动推断字段名联合类型
要让TypeScript保留spec中字符串字面量的具体类型(而非自动拓宽为string),给spec添加as const断言即可,这样TypeScript会把每个name的值当作字面量类型处理:
const spec = [ { name: "Field 1", start: 1, width: 4, padding_position: "end", }, { name: "Field 2", type: "int", start: 5, width: 5, padding_symbol: "0", }, { name: "Field 3", start: 10, width: 20, padding_position: "end", }, { name: "Field 4", start: 30, width: 2, padding_position: "end", }, ] as const; // 自动推断FieldName为 "Field 1" | "Field 2" | "Field 3" | "Field 4" type FieldName = typeof spec[number]['name']; // 现在dataToSerialize会自动验证键的合法性 const dataToSerialize: { [K in FieldName]?: string | number } = { "Field 1": "value" }; // 错误示例:使用不存在的键会报错 // const invalidData: { [K in FieldName]?: string | number } = { "Field 5": "value" };
额外需求实现:根据type映射对应值类型
先定义type字段到值类型的映射关系,再通过映射类型遍历spec中的每个字段,自动生成对应键的类型约束:
// 定义type到值类型的映射 type TypeToValue = { int: number; // 可扩展其他类型,比如string、boolean等 string: string; }; // 从spec中提取单个字段的类型 type SpecField = typeof spec[number]; // 生成每个字段对应的键值对类型 type DataToSerialize = { [F in SpecField as F['name']]?: F extends { type: infer T } ? T extends keyof TypeToValue ? TypeToValue[T] : string | number : string | number; }; // 现在dataToSerialize会根据type自动约束值类型 const dataToSerialize: DataToSerialize = { "Field 1": "value", // 正确,无type默认允许string/number "Field 2": 123 // 正确,type为int,值必须是number }; // 错误示例:Field 2传入字符串会报错 // const invalidData: DataToSerialize = { "Field 2": "123" };
这个实现逻辑:
- 当字段有
type且该type在TypeToValue中存在时,值类型会被严格约束为对应类型 - 当字段无
type或type不在映射中时, fallback到string | number
内容的提问来源于stack exchange,提问作者acjay
相关产品推荐
相关产品推荐

