TypeScript重写含装饰器的父类方法后如何获取最终方法实现
问题:子类重写装饰器修饰的父类方法后,如何获取子类的方法实现?
当前代码中,子类Child重写了父类Parent中带有装饰器@D()的doSomething方法,但通过装饰器存入对象a的doSomething方法调用时,输出的仍是父类的'parent',而非子类的'child'。请问如何获取最终的子类方法实现?
代码示例
const a = {} as any class Parent { @D() public doSomething(b: any) { console.log('parent') } } class Child extends Parent{ public override doSomething() { console.log('child') } } const child = new Child() child.doSomething() function D () { return function(target: any, property: string, descriptor: PropertyDescriptor) { console.log('assign') a[property] = target[property] } } setTimeout(a.doSomething, 1000) // 此处输出"parent",期望输出"child"
问题原因
装饰器是在类定义阶段执行的:当Parent类被装饰时,D装饰器直接把Parent.prototype.doSomething的引用存到了a对象里。而子类Child重写方法是在子类定义时修改Child.prototype,这不会改变a里已经存储的父类方法引用,所以调用a.doSomething时自然输出父类的结果。
解决方案
根据使用场景,有两种常用处理方式:
方案1:通过实例动态调用(通用推荐)
修改装饰器逻辑,不直接存储方法引用,而是存储一个接收实例的代理函数。调用时传入子类实例,利用原型链查找自动获取子类的重写方法:
const a = {} as any class Parent { @D() public doSomething(b: any) { console.log('parent') } } class Child extends Parent{ public override doSomething() { console.log('child') } } const child = new Child() child.doSomething() function D () { return function(target: any, property: string, descriptor: PropertyDescriptor) { console.log('assign') // 存储代理函数,接收实例和参数 a[property] = (instance: any, ...args: any[]) => { instance[property](...args) } } } // 调用时传入子类实例 setTimeout(() => a.doSomething(child), 1000) // 输出"child"
方案2:手动更新子类方法引用(适合确定子类的场景)
如果已经明确最终会使用Child子类,可以在子类定义完成后,手动将子类原型的方法更新到a对象中:
const a = {} as any class Parent { @D() public doSomething(b: any) { console.log('parent') } } class Child extends Parent{ public override doSomething() { console.log('child') } } // 子类定义后,更新a中的方法引用 a.doSomething = Child.prototype.doSomething const child = new Child() child.doSomething() function D () { return function(target: any, property: string, descriptor: PropertyDescriptor) { console.log('assign') a[property] = target[property] } } setTimeout(a.doSomething, 1000) // 输出"child"
补充说明
- 方案1更通用,不管后续有多少个子类重写方法,只要传入对应子类的实例就能调用到正确的方法;
- 方案2更直接,但依赖于明确知道最终使用的子类,灵活性稍差。
内容的提问来源于stack exchange,提问作者Oki
相关产品推荐
相关产品推荐

