有什么办法自定义属性装饰器吗?

装饰器规范都在逐渐的改进,版本都不怎么兼容,有 stage2 stage3…stage4 ; Class Fields 提案分为set语义、define语义 ,不同版本排列组合再结合上Object.defineProperty 可能产生莫名奇妙的问题,不知道你想用的是哪种

因为属于基础问题,只提供解决思路。
首先cocos不存在支不支持ts语法的问题。 问题核心 是cocos内嵌 ts是哪个版本, ts装饰器语法迭代很快,你要确保你使用的是cocos内嵌ts支持的那个stage.

另外,过程中如果有不明确的细节, 可以查看cocos编译生成的js产物, 看看装饰器被翻译成了啥

这点蛮蛋疼的,之前2.4自己写的可以用的装饰器到3.8版本就都用不了了。

先看看3.8文档写没写用的 ts是多少。
那可能是升级了。。。。

懒得去找了,反正装饰器也不是一定得用。还是等真的稳定了再考虑要不要用

没毛病,类装饰器、方法装饰器都没问题,唯独属性装饰器不好使,不知道到底是babel兼容问题,还是cocos 封装属性序列化导致的副作用。

这里有坑,babel也在做ts的编译,如果用babel编译ts,你会发现有些细节 tsc编译实现的都不一样。。 cocos应该用的是tsc; 这种语法糖建议少玩, 玩脱了到时候自己都hold不住

babel是在tsc之后吧。。。。

传统的是tsc转完了再用babel, 现在babel也出了babel-typescript 一步到位 抢tsc饭碗

QQ20250520-170636
完全没问题

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。啊

属性装饰器可以用的啊

属性装饰器可以用的,你这个就是没有return
可以参考这个

实测了部分 CocosCreator 版本,
3.8.0 是 TypeScript 4.3.5
3.8.6 是 TypeScript 4.9.5

https://gitee.com/yeshao2069/cocos-creator-faq/blob/master/Select/support/typescript-support.md

高质量高质量 mark

果然论坛要经常翻一翻,看来就是babel导致的。
感谢发出来的链接,算是解决了个大问题。

自定义装饰器在3.8.3~3.8.6都没问题啊,下面的代码都是我自定义装饰器的应用,正式发布到微信小程序都能运行正常。

import { Facade, IConvertor, KdField, KdNumeric, StringUtils } from "../../core/Kaka";
import CsvConfManager from "../CsvConfManager";
import { ToLangValue, ToString } from "../CsvConvertors";
import { ConfOther, ConfOtherManager } from "./ConfOtherManager";
import { ConfSkill, ConfSkillManager } from "./ConfSkillManager";

export class ToSkill implements IConvertor<ConfSkill> {
    public cast(v: string): ConfSkill {
        if (!v || v == '') return undefined;
        return ConfSkillManager.getInstance().get(Number(v));
    }
}

export class ConfItem {
    public id: number;
    @KdField("name", ToLangValue)
    public name: string;
    @KdField("describe", ToLangValue)
    public describe: string;
    @KdField("icon", ToString)
    public icon: string;
    public type: number;
    public targetType: number;
    @KdField("skillId", ToSkill)
    public skill: ConfSkill;
    public dailyNum: number;
    @KdField("access", ToLangValue)
    public access: string;
}

/**
 * 道具数据管理
 * 
 * @author zkpursuit
 */
@KdNumeric("item.csv", ConfItem)
export class ConfItemManager extends CsvConfManager<ConfItem> {

    public static readonly lingShiId: number = 101;
    public static readonly lingShiIcon: string = '101';

    private static instance: ConfItemManager;
    public static getInstance(): ConfItemManager {
        if (this.instance == null) {
           this.instance = Facade.getInstance().retrieveProxy(ConfItemManager);
        }
        return this.instance;
    }

    private list: ConfItem[] = [];
    private map: Map<number, ConfItem> = new Map<number, ConfItem>();
    private map1: Map<number, ConfItem[]> = new Map<number, ConfItem[]>();

    protected parseBefore(): void {
        this.list.length = 0;
        this.map.clear();
        this.map1.clear();
    }
    protected cacheObject(info: ConfItem) {
       if (info.access === 'null') {
            info.access = null;
        } else if (info.access && info.access !== '') {
            let confOther: ConfOther = ConfOtherManager.getInstance().get();
            if (info.id === confOther.relief[1]) {
                info.access = StringUtils.format(info.access, confOther.relief[0]);
            } else if (info.dailyNum !== 0) {
               info.access = StringUtils.format(info.access, Math.abs(info.dailyNum));
            }
        }
        this.list.push(info);
        this.map.set(info.id, info);
        let arr: ConfItem[] = this.map1.get(info.targetType);
        if (!arr) {
            arr = [];
           this.map1.set(info.targetType, arr);
        }
        arr.push(info);
    }
    protected parseAfter(): void {
        //console.log(this);
    }

    public get(id: number): ConfItem {
        return this.map ? this.map.get(id) : null;
    }

    public getList(targetType?: number): ConfItem[] {
        if (!targetType || targetType < 0) return this.list;
        return this.map1.get(targetType);
    }

}

属性装饰器本身能用的,cocos自带的“@property”不就是嘛,只不过部分功能会有些出入,目前3.x版本应该都有这问题——如果你的属性装饰器内携带了“Object.defineProperty”,会发现其不生效。出问题的原因已经有人说过了,babel的版本问题。这里看示例图比较明显:


问题原因——属性装饰器修饰的是原型链,而babel又在该类的构造函数内对实例对象同样修饰了该属性,因此当从实例化对象获取该属性时,优先从对象自身获取,导致我们原本的装饰器的功能“被拦截了”。
解决方式1、构造函数内,对自身拥有且原型链拥有的属性进行剔除即可(当然有必要时才清):

解决方式2、通过理清其原理,只要在属性装饰器返回一个不携带"initializer"的装饰对象即可防止"_initializerDefineProperty"又对实例对象添加属性,实现方式一行return即可:

其可行性的来源如下:
![image|690x273] (upload://7rEaANbNfWg7gh7BHaA1QWfjTdh.png)
不过该方式改动虽简单,但是保不准cocos升级又调整的话就难说了 :upside_down_face:

兄弟研究得很深入了。
已经使用前面哥们提供的链接,使用Object.assign解决问题了。

搜嘎,还有方案,俺也看看:grinning: