TypeScript类型适配问题:实现输入输出键对应类转换函数
问题解决:动态生成对应类实例的函数实现
错误原因分析
- Type 'string' is not assignable to type 'keyof OutputObject':原代码泛型
K extends keyof TObj中,TObj是Partial<InputObject>,TypeScript无法确定遍历的键属于keyof OutputObject,导致类型不匹配。 - Type 'Partial
' is not assignable to type 'Pick<OutputObject, K>' :Partial<OutputObject>允许所有字段可选,但Pick<OutputObject, K>要求选中的K字段必须存在且类型匹配,二者类型不兼容。
优化后的实现方案
通过类型映射和动态遍历输入键解决问题,同时让函数支持后续扩展新字段:
class A { constructor(public value: number) {} // 接收初始化数值 } class B { constructor(public value: number) {} } // 集中管理输入键与对应类的映射,新增字段只需在此添加 type ClassMap = { a: typeof A; b: typeof B; // 后续新增c、d时,直接添加:c: typeof C; d: typeof D; }; // 自动推导输入类型:每个键对应可选的number类型 type InputObject = { [K in keyof ClassMap]?: number }; // 自动推导输出类型:每个键对应对应类的实例 type OutputObject = { [K in keyof ClassMap]: InstanceType<ClassMap[K]> }; const fn = <K extends keyof ClassMap>(x: Pick<InputObject, K>): Pick<OutputObject, K> => { const returnValue = {} as Pick<OutputObject, K>; // 动态遍历输入键,避免硬编码,提升扩展性 for (const key in x) { if (x[key] !== undefined) { const ClassConstructor = ClassMap[key]; returnValue[key] = new ClassConstructor(x[key]!) as InstanceType<ClassMap[K]>; } } return returnValue; }; // 测试用例 const result1 = fn({ a: 1, b: 1 }); // { a: A, b: B } const result2 = fn({ b: 2 }); // { b: B } const result3 = fn({}); // {}
代码说明
- 类型映射
ClassMap:统一管理输入键与类的关联,新增字段时只需在此添加对应关系,无需修改函数逻辑。 - 自动推导类型:利用TypeScript映射类型,从
ClassMap自动生成InputObject和OutputObject,减少重复定义。 - 动态遍历处理:通过
for...in遍历输入对象的键,动态创建对应类的实例,避免硬编码a、b。 - 类型断言:使用
as Pick<OutputObject, K>和as InstanceType<ClassMap[K]>帮助TypeScript正确推断类型,解决类型不匹配问题。
原代码报错核心原因
- 原泛型定义未明确关联
K与OutputObject的键,导致TypeScript无法确认键的合法性。 Partial<OutputObject>是全可选类型,但函数返回的应该是输入存在的键必须对应存在实例的类型,二者类型不兼容,因此需要使用Pick<OutputObject, K>配合类型断言确保类型正确。
内容的提问来源于stack exchange,提问作者Islander44
相关产品推荐
相关产品推荐

