装饰器规范都在逐渐的改进,版本都不怎么兼容,有 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饭碗
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。啊
属性装饰器可以用的啊
属性装饰器可以用的,你这个就是没有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升级又调整的话就难说了
兄弟研究得很深入了。
已经使用前面哥们提供的链接,使用Object.assign解决问题了。
搜嘎,还有方案,俺也看看






