TypeScript:如何根据传入的子类类型推导对应选项类型
问题
给定第三方不可修改的类结构:
class Parent {} class Child1 extends Parent {} class Child2 extends Parent {}
需要实现函数doSomething,接收子类实例和对应选项,不同子类要求不同的选项结构,需实现选项的自动补全与类型校验。
最初尝试用索引接口定义选项类型,但无法将类作为索引类型:
interface SomeOptions { Child1: {foo: string}, Child2: {id: number}, }
改为数组形式的类型定义:
type SomeOptions = [ {class: Child1, options: {foo: string}}, {class: Child2, options: {id: number}}, ]
现在需要实现类型FindMeTheCorrectOption<T>,让函数:
const doSomething = <T extends Parent>(someClass: T, options: FindMeTheCorrectOption<T>) => {}
能根据传入的子类实例自动匹配对应选项类型,达到以下效果:
doSomething(new Child1(), {foo: 'bar'}); // 类型合法 doSomething(new Child2(), {id: 1}); // 类型合法 doSomething(new Child2(), {foo: 1}); // TypeScript报错,foo应为string类型
请问如何实现该类型推导?
解决方案
1. 修正选项映射的类型定义
首先需要把数组形式的SomeOptions中class字段的类型改为构造函数类型(typeof Child1而非实例类型Child1),这样才能通过实例的构造函数关联选项:
type SomeOptions = [ {class: typeof Child1, options: {foo: string}}, {class: typeof Child2, options: {id: number}}, ];
基于这个数组,转换为以构造函数为键、选项类型为值的映射类型:
type ClassToOptions = { [Item in SomeOptions[number] as Item['class']]: Item['options'] };
2. 实现FindMeTheCorrectOption<T>
通过实例类型T获取其构造函数类型,再到ClassToOptions中查找对应选项:
type FindMeTheCorrectOption<T extends Parent> = ClassToOptions[typeof T];
3. 最终函数实现
将类型代入函数定义即可:
const doSomething = <T extends Parent>(someInstance: T, options: FindMeTheCorrectOption<T>) => {};
验证效果
此时代码会按预期工作:
doSomething(new Child1(), {foo: 'bar'}):类型校验通过doSomething(new Child2(), {id: 1}):类型校验通过doSomething(new Child2(), {foo: 1}):TypeScript抛出错误,提示选项结构不匹配
扩展说明
后续新增子类时,只需在SomeOptions数组中添加对应的{class: typeof 子类, options: 对应选项类型}条目,映射类型和推导逻辑会自动适配新的子类,无需修改其他代码。
内容的提问来源于stack exchange,提问作者Robin Schambach
相关产品推荐
相关产品推荐

