如何正确编写对象转换器的TypeScript类型定义
修正TypeScript映射类型,使键与对应取值类型严格匹配
问题背景
现有如下TypeScript对象与类型定义:
const schema = { student: {id: 'student/student'}, students: {id: 'student/students'}, } as const; interface Schema { readonly [key: string]: {id: string}; } type Mapped<V extends Schema, U extends keyof V> = { [S in V[U]['id']]: V[U]; }
当前使用Mapped<typeof schema, keyof typeof schema>时,所有值可被赋值给任意键,例如以下错误代码仍能通过类型检查:
const a: Mapped<typeof schema, keyof typeof schema> = { 'student/student': {id: 'student/student'}, 'student/students': {id: 'student/student'}, // 错误赋值但未被拦截 }
解决方案
原Mapped类型的问题在于:遍历的键是V[U]['id']的联合类型,而值类型是V[U]的联合类型,导致每个键都接受所有可能的联合类型值。需要通过键重映射实现键与值的一一对应:
修改后的Mapped类型如下:
type Mapped<V extends Schema> = { [K in keyof V as V[K]['id']]: V[K]; };
原理说明
- 使用
as关键字进行键重映射:遍历原Schema的每个键K,将V[K]['id']作为新对象的键 - 每个新键对应的值类型严格绑定为原对象中
K对应的值类型V[K],实现键与值的精准匹配
验证示例
使用修正后的类型,错误赋值会被TypeScript正确拦截:
// 正确示例:每个键对应正确的取值类型 const a: Mapped<typeof schema> = { 'student/student': {id: 'student/student'}, 'student/students': {id: 'student/students'}, }; // 错误示例:TypeScript会报错,因为'student/students'键只能接受{id: 'student/students'}类型 const b: Mapped<typeof schema> = { 'student/student': {id: 'student/student'}, 'student/students': {id: 'student/student'}, // 类型不匹配,报错 };
内容的提问来源于stack exchange,提问作者Florat
相关产品推荐
相关产品推荐

