TypeScript中如何验证构造函数参数类是否继承自指定类?
嘿,这个问题其实在TypeScript开发中挺典型的——既要利用TS的类型系统做编译时保障,又得考虑运行时的健壮性(毕竟TS编译后类型信息就没了)。我给你分两部分来拆解解决方案:
解决方案:编译时类型约束 + 运行时验证
1. 编译时:用TypeScript类型系统拦截非法参数
首先,我们可以通过泛型+构造函数类型,让TS在编译阶段就帮你把住关,直接阻止非Foo子类的类传入Bar的构造函数。
举个实际的代码例子:
// 父类Foo class Foo { // 所有子类共享的属性 sharedProp: string = "default"; } // 子类Baz class Baz extends Foo { // Baz的专属属性/方法 bazProp: number = 123; } // 定义Bar类,用泛型约束model的类型 class Bar<T extends Foo> { constructor(private model: new () => T) { // 后续可以用this.model创建实例,比如: const instance = new this.model(); console.log(instance.sharedProp); // 能直接访问Foo的属性 } } // ✅ 合法调用:Baz是Foo的子类,TS不会报错 const validBar = new Bar(Baz); // ❌ 编译报错:NotFoo不是Foo的子类,TS直接提示类型不兼容 class NotFoo {} const invalidBar = new Bar(NotFoo);
这里的new () => T表示一个能生成T实例的构造函数类型,而T extends Foo则强制约束T必须是Foo的子类,编译阶段就帮你拦截了非法输入。
2. 运行时:验证类确实继承自Foo
如果担心有人绕过TS的类型检查(比如用any传参,或者在纯JS环境中调用这段代码),那必须加上运行时验证逻辑。我们可以通过检查类的原型链来实现:
修改Bar的构造函数,加上运行时校验:
class Bar<T extends Foo> { constructor(private model: new () => T) { // 运行时校验:检查model的原型链是否包含Foo if (!(model.prototype instanceof Foo)) { throw new Error("错误:传入的类必须继承自Foo!"); } // 你的业务逻辑... } }
如果需要更严谨的原型链检查(比如避免某些原型链篡改的情况),可以手动遍历原型链:
class Bar<T extends Foo> { constructor(private model: new () => T) { let currentProto = Object.getPrototypeOf(model.prototype); let isSubclass = false; // 遍历原型链,直到找到Foo.prototype或走到顶端 while (currentProto) { if (currentProto === Foo.prototype) { isSubclass = true; break; } currentProto = Object.getPrototypeOf(currentProto); } if (!isSubclass) { throw new Error("错误:传入的类必须继承自Foo!"); } } }
额外小技巧:提取验证逻辑为工具函数
如果多个地方都需要做这种子类检查,可以把验证逻辑抽成工具函数,复用起来更方便:
/** * 检查某个类是否是另一个类的子类 * @param child 待检查的子类构造函数 * @param parent 父类构造函数 */ function isSubclassOf(child: new () => any, parent: new () => any): boolean { let currentProto = Object.getPrototypeOf(child.prototype); while (currentProto) { if (currentProto === parent.prototype) { return true; } currentProto = Object.getPrototypeOf(currentProto); } return false; } // 在Bar中使用这个工具函数 class Bar<T extends Foo> { constructor(private model: new () => T) { if (!isSubclassOf(model, Foo)) { throw new Error("错误:传入的类必须继承自Foo!"); } } }
内容的提问来源于stack exchange,提问作者Ohgodwhy
相关产品推荐
相关产品推荐

