TypeScript 的 target 配置影响代码生成的方式,尤其是在 ES2022 及更高版本中,对类字段初始化和访问器 (getter/setter) 的处理发生了显著变化,会导致colyseus/schema 的序列化/反序列化出现undefined问题。
1. 高版本 (ES2022 及以上) 的行为
原因:
1.类字段的定义方式变化: 在 ES2022 中,JavaScript 的类字段引入了标准化的私有字段和公有字段语法。TypeScript 编译器在 target 设置为 ES2022 或更高版本时,会生成与此标准兼容的类字段定义代码。
// ES2022+ 的类字段初始化
class RankingEntry {
player = "";
score = 0;
}
与较低版本不同,这种方式不再使用访问器(getter/setter)来包装字段,而是直接将字段作为实例的直接属性。
2.@colyseus/schema 的序列化/反序列化问题: @colyseus/schema 依赖于类字段的 getter/setter 来监听字段变化,以便触发相关状态的同步操作。在高版本中,由于类字段的初始化方式改变,@colyseus/schema 无法正确绑定字段的访问器,导致字段的序列化结果为 undefined。
特性影响:
@type()定义的字段,虽然初始化成功,但由于@colyseus/schema无法拦截字段的设置操作,字段的值无法被正确序列化,导致输出的字段值为undefined。
2. 低版本 (ES2021 及以下) 的行为
原因:
1. 类字段的访问器 (getter/setter): 在 ES2021 及更低版本中,TypeScript 会通过访问器 (getter 和 setter) 实现类字段的定义。这与 @colyseus/schema 的设计完全兼容,因为 @colyseus/schema 正是通过这些访问器来监听字段的变更并执行状态同步的。
// ES2021 及更低版本的字段初始化
Object.defineProperty(RankingEntry.prototype, "player", {
get() { return this.__player; },
set(value) { this.__player = value; /* 通知 schema 变更 */ },
});
2. @colyseus/schema 的监听机制: 这种实现方式让 @colyseus/schema 能正确监控字段值的变更,因此字段的值可以被正确序列化。
特性影响:
- 所有字段都被正确地序列化,并且通过
toJSON()或直接访问时,字段的值可以被正确打印。
3.解决方法
为了兼容 @colyseus/schema 的监听机制并避免 ES2022+ 的类字段语法问题,可以通过以下方式解决:
1. 降级 target 到 ES2021 或更低版本
- 修改
tsconfig.json:
{
"compilerOptions": {
"target": "ES2021",
// 其他配置
}
}
这种方式简单有效,完全兼容 @colyseus/schema 的特性。
2. 强制使用访问器
即使使用高版本的 target,也可以通过显式定义 getter/setter 来兼容 @colyseus/schema:
import { Schema, type } from "@colyseus/schema";
export class RankingEntry extends Schema {
private _player: string = "";
private _score: number = 0;
@type("string")
get player() {
return this._player;
}
set player(value: string) {
this._player = value;
}
@type("number")
get score() {
return this._score;
}
set score(value: number) {
this._score = value;
}
constructor(player = "Unknown", score = 0) {
super();
this.player = player;
this.score = score;
}
}
优点:兼容高版本 target 和 @colyseus/schema。 缺点:需要手动为所有字段添加 getter/setter。
总结
- 推荐方案:将
tsconfig.json中的target降级到ES2021或更低版本。 - 如果必须使用高版本
target,则需要显式为@colyseus/schema中的字段定义getter/setter,以确保正确的序列化和监听。
6万+

被折叠的 条评论
为什么被折叠?



