You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript多装饰器修饰属性时仅外层setter/getter执行问题

问题原因

内层装饰器setter/getter未触发的核心原因有两点:

  • 多层装饰器叠加执行时,外层装饰器直接覆盖了内层装饰器定义在PropertyDescriptor上的存取器方法,没有保留内层方法的引用,最终挂载到属性上的只有最外层装饰器的get/set逻辑。
  • 装饰器执行顺序符合如下规则:
    • 装饰器工厂函数(即Decorator1()、Decorator2()本身)从上到下求值
    • 求值得到的实际装饰器逻辑从下到上(从内到外)调用
      对应代码逻辑,会先执行内层Decorator2给descriptor写入存取器,再执行外层Decorator1,直接重写descriptor的get/set字段,内层写入的逻辑被完全覆盖,因此运行时不会触发。
      另外原有存取器实现仅打印日志,没有维护实际属性值、也没有调用上层逻辑,即使不被覆盖也无法实现属性的正常读写。
修复方案

每层装饰器重写get/set前,先保存当前descriptor上已有的存取器引用,自身逻辑执行完成后链式调用上一层的存取器,同时维护属性的实际存储值即可,修复后的装饰器代码如下:

export function Decorator1(): any {
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
    descriptor = descriptor || {};
    console.log('Init Decorator 1');
    // 保存内层装饰器已定义的存取器
    const originalGet = descriptor.get;
    const originalSet = descriptor.set;
    let storedValue: any;

    descriptor.get = function (this: any) {
      console.log('Get Decorator 1');
      // 优先调用内层get逻辑
      if (originalGet) return originalGet.call(this);
      return storedValue;
    }

    descriptor.set = function (this: any, newValue: any) {
      console.log('Set Decorator 1');
      // 优先调用内层set逻辑
      if (originalSet) {
        originalSet.call(this, newValue);
        return;
      }
      storedValue = newValue;
    }

    return descriptor;
  }
}

export function Decorator2(): any {
  return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
    descriptor = descriptor || {};
    console.log('Init Decorator 2');
    const originalGet = descriptor.get;
    const originalSet = descriptor.set;
    let storedValue: any;

    descriptor.get = function (this: any) {
      console.log('Get Decorator 2');
      if (originalGet) return originalGet.call(this);
      return storedValue;
    }

    descriptor.set = function (this: any, newValue: any) {
      console.log('Set Decorator 2');
      if (originalSet) {
        originalSet.call(this, newValue);
        return;
      }
      storedValue = newValue;
    }

    return descriptor;
  }
}
修复后运行结果

执行代码后日志输出如下,两层装饰器的存取器逻辑都会按从外到内的顺序触发:

[LOG]: "Init Decorator 2" 
[LOG]: "Init Decorator 1" 
[LOG]: "Set Decorator 1" 
[LOG]: "Set Decorator 2" 
[LOG]: "Set Decorator 1" 
[LOG]: "Set Decorator 2"

内容的提问来源于stack exchange,提问作者Get Off My Lawn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:36:26