TypeScript如何基于第一个泛型参数条件关联第二个泛型参数
实现方案
你需要使用TypeScript编译期的条件类型来实现泛型参数的依赖关联,不能使用运行时运算符instanceof做泛型约束判断,具体实现如下:
步骤1:定义类型映射规则
先声明一个工具类型,根据传入的原始类型匹配对应的构造函数类型:
type ClassForType<T extends string | number> = T extends string ? typeof StringClass : typeof NumberClass;
步骤2:改写泛型类
这里提供两种写法,按需选择即可:
写法1:省略第二个泛型参数(推荐)
因为B的类型完全由A决定,不需要额外声明第二个泛型,减少冗余:
class Test<A extends string | number> { // val存储的是类实例,使用InstanceType工具类取构造函数对应的实例类型 val: InstanceType<ClassForType<A>>; constructor(val: A, Class: ClassForType<A>) { this.val = new Class(val); } }
写法2:保留第二个泛型参数
如果有场景需要显式声明第二个泛型,可以用约束+默认值的形式:
class Test< A extends string | number, B extends ClassForType<A> = ClassForType<A> > { val: InstanceType<B>; constructor(val: A, Class: B) { this.val = new Class(val); } }
验证效果
写测试用例可以看到类型约束已经生效:
// 传入字符串时,只允许传入StringClass构造函数 new Test('test', StringClass); // 编译通过 new Test('test', NumberClass); // 编译报错:类型不匹配 // 传入数字时,只允许传入NumberClass构造函数 new Test(123, NumberClass); // 编译通过 new Test(123, StringClass); // 编译报错:类型不匹配
注意点
- 你原有代码中
val: B的定义存在问题:B是构造函数的类型,new Class(val)返回的是类实例,需要用InstanceType<B>获取对应的实例类型赋值给val。 instanceof是运行时运算符,不能用在编译期的泛型约束中,同时原始类型string/number的判断用instanceof本身也不符合预期,只有包装对象才会满足instanceof String/Number的判断。
内容的提问来源于stack exchange,提问作者Max Gordon
相关产品推荐
相关产品推荐

