TypeScript中基于类型而非类型映射的更简洁实现方案
解决方法
你遇到的核心问题是TypeScript类型信息在运行时不可用,所以需要找到编译时确保类型与运行时逻辑同步的方案,避免手动维护额外列表。下面是几种可行的方法:
方法一:用示例对象同步类型与运行时判断
创建一个符合Record接口的示例对象(填充默认值),通过这个对象在运行时判断列类型。新增列时TypeScript会强制你给示例对象添加对应属性,确保两者同步:
// 定义示例对象,必须完全符合Record接口 const recordExample: Record = { age: 0, ID: 0, item1: 0, item2: '', item3: '', item4: 0, // 新增列时,这里必须添加对应默认值,否则编译器报错 }; // 根据列名获取类型的函数 function getColumnType(column: keyof Record): 'number' | 'string' { return typeof recordExample[column]; } // 业务逻辑处理 function handleColumnSelect(column: keyof Record) { switch(getColumnType(column)) { case 'string': functionB(column); break; case 'number': functionA(column); break; } }
这个方法的优势是完全依赖TypeScript的类型检查强制同步,不需要手动维护映射列表,新增列时编译器会自动提醒你更新示例对象,从根源上避免技术债务。
方法二:用类型工具强制列列表与接口同步
如果你更倾向于维护列列表而非示例对象,可以用TypeScript的类型工具确保列表包含所有对应类型的列,新增列时编译器会报错提醒:
// 从Record接口中提取所有number类型的键 type NumberColumns = { [K in keyof Record]: Record[K] extends number ? K : never }[keyof Record]; // 提取所有string类型的键 type StringColumns = { [K in keyof Record]: Record[K] extends string ? K : never }[keyof Record]; // 定义列列表,用const断言确保类型严格 const numberColumns = ['age', 'ID', 'item1', 'item4'] as const satisfies readonly NumberColumns[]; const stringColumns = ['item2', 'item3'] as const satisfies readonly StringColumns[]; // 类型守卫函数,判断列是否为string类型 function isStringColumn(column: keyof Record): column is StringColumns { return (stringColumns as readonly string[]).includes(column); } // 业务逻辑处理 function handleColumnSelect(column: keyof Record) { if (isStringColumn(column)) { functionB(column); } else { functionA(column); } }
这里用satisfies关键字确保列列表的类型与NumberColumns/StringColumns完全匹配,新增列时如果忘记更新对应列表,编译器会直接报错,强制你同步维护。
方法三:用TypeScript Transformer自动生成映射
如果项目复杂度允许,可以使用ts-transformer-keys这类编译时工具,自动从Record接口提取键和类型信息,生成运行时可用的映射:
- 安装依赖:
npm install ts-transformer-keys --save-dev - 配置TypeScript transformer(具体配置可参考工具文档)
- 使用工具生成映射:
import { keys } from 'ts-transformer-keys'; // 自动获取Record的所有键 const allRecordKeys = keys<Record>(); // 结合类型工具生成类型映射(需要额外的transformer支持类型提取) const typeMapping = allRecordKeys.reduce((map, key) => { map[key] = typeof ({} as Record)[key] === 'number' ? 'number' : 'string'; return map; }, {} as { [K in keyof Record]: 'number' | 'string' });
这个方法完全自动化,不需要手动维护任何列表,但需要配置额外的编译工具,适合大型项目使用。
内容的提问来源于stack exchange,提问作者Zane Neelin
相关产品推荐
相关产品推荐

