TypeScript如何动态推断parse与serialize方法的关联类型
如何实现TypeScript中
parse返回类型与serialize入参类型的动态绑定 无泛型的QUESTION类型写法无法生效的核心原因:类型中使用any作为parse返回值,ReturnType<QUESTION['parse']>只会拿到固定的any类型,无法和单个Question实例的parse返回值做关联,自然也没法校验serialize的入参类型。
不需要手动硬编码泛型参数,通过泛型辅助函数反向推断即可实现自动的类型关联,实现代码如下:
核心类型与辅助函数定义
// 基础泛型Question类型,T为parse返回值、serialize入参的绑定类型 type QUESTION<T = unknown> = { parse: (value: string) => T serialize: (value: T) => string } // 单个Question构造辅助函数,自动从传入对象推断T类型 function defineQuestion<T>(q: QUESTION<T>): QUESTION<T> { return q } // Question数组构造辅助函数,支持不同T类型的Question组成异构数组 function defineQuestionList<T extends readonly QUESTION<any>[]>(list: T): T { return list }
实际使用效果
使用辅助函数定义Question列表时,TS会自动推断每个Question的泛型参数,不需要手动标注:
const idsQuestions = defineQuestionList([ defineQuestion({ parse: (input) => input.split('\n'), // ids自动推断为string[],类型提示、校验正常生效 serialize: (ids) => ids.join('\n') }), defineQuestion({ parse: (input) => input.split('\n').reduce((acc, id) => ({ ...acc, [id]: true, // 给reduce初始值加类型断言,避免TS推断为{}类型 }), {} as Record<string, boolean>), // ids自动推断为Record<string, boolean> serialize: (ids) => Object.keys(ids).join('\n') }) ])
错误写法会在编译阶段直接抛出类型错误:
// 编译直接报错:类型"boolean"上不存在属性"join" const questionWithError = defineQuestion({ parse: () => false, serialize: (ids) => ids.join('\n') })
原理说明
- 如果直接标注变量类型为
QUESTION[],TS会将数组元素宽化为统一的无泛型约束类型,丢失每个Question实例自身parse和serialize的类型绑定关系 - 泛型辅助函数会触发TS的类型反向推断:从传入对象的
parse方法返回值自动推导泛型T的实际类型,再将T绑定到同个对象的serialize入参上,实现两个方法的类型关联 - 整个过程不需要手动指定任何泛型参数,所有类型推导由TS自动完成
内容的提问来源于stack exchange,提问作者Matheus Vellone
相关产品推荐
相关产品推荐

