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

TypeScript类属性装饰器无法正确覆盖实例的Get/Set方法

问题原因

你写的属性装饰器是给类的原型对象添加了bar的getter,但类中bar = 0的写法属于实例属性初始化——TypeScript会把这段代码编译到类的构造函数里,执行this.bar = 0,这会在实例本身上创建一个同名的自有属性。由于JS中实例自有属性的优先级高于原型属性,所以访问foo.bar时会直接读取实例上的0,而不是原型上的getter返回的42。

解决方案

以下是几种可行的解决方式,你可以根据场景选择:

方案1:将类属性改为访问器(getter)

把实例属性改成原型访问器,这样构造函数不会给实例赋值自有属性,装饰器可以直接覆盖原型上的访问器逻辑:

function Decorator() {
    return function (target: Object, propertyKey: string) {
        Object.defineProperty(target, propertyKey, {
            get: function () {
                return 42;
            },
            configurable: true,
            enumerable: true
        });
    };
}

export class Foo {
    @Decorator()
    get bar() {
        return 0; // 原逻辑会被装饰器覆盖
    }
}

const foo = new Foo();
console.log(foo.bar); // 输出42

方案2:修改构造函数,实例初始化后覆盖属性

如果必须保留bar = 0的实例属性写法,可以通过修改类的构造函数,在实例创建完成后重新定义实例上的属性,覆盖构造函数设置的自有值:

function Decorator() {
    return function (target: any, propertyKey: string) {
        const originalConstructor = target.constructor;
        
        // 替换原构造函数
        target.constructor = function (...args: any[]) {
            const instance = new originalConstructor(...args);
            // 给实例添加getter,覆盖自有属性
            Object.defineProperty(instance, propertyKey, {
                get: () => 42,
                configurable: true
            });
            return instance;
        };
        
        // 维持原型链的一致性
        target.constructor.prototype = originalConstructor.prototype;
    };
}

export class Foo {
    @Decorator()
    bar = 0;
}

const foo = new Foo();
console.log(foo.bar); // 输出42

方案3:类装饰器批量处理属性(多属性场景)

先通过属性装饰器标记需要处理的属性,再用类装饰器统一修改构造函数,批量处理所有标记的属性:

// 存储类与需要装饰的属性的映射
const targetPropsMap = new Map<Function, string[]>();

function Decorator() {
    return function (target: any, propertyKey: string) {
        const constructor = target.constructor;
        if (!targetPropsMap.has(constructor)) {
            targetPropsMap.set(constructor, []);
        }
        targetPropsMap.get(constructor)!.push(propertyKey);
    };
}

// 类装饰器:应用属性装饰逻辑
function ApplyPropertyDecorators() {
    return function (constructor: Function) {
        const originalConstructor = constructor as any;
        const newConstructor = function (...args: any[]) {
            const instance = new originalConstructor(...args);
            // 批量处理所有标记的属性
            const props = targetPropsMap.get(constructor);
            if (props) {
                props.forEach(prop => {
                    Object.defineProperty(instance, prop, {
                        get: () => 42,
                        configurable: true
                    });
                });
            }
            return instance;
        };
        // 保持原型继承关系
        newConstructor.prototype = originalConstructor.prototype;
        return newConstructor as any;
    };
}

@ApplyPropertyDecorators()
export class Foo {
    @Decorator()
    bar = 0;
    
    @Decorator()
    baz = 100;
}

const foo = new Foo();
console.log(foo.bar); // 输出42
console.log(foo.baz); // 输出42

内容的提问来源于stack exchange,提问作者user18156

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 11:47:53