colyseus/schema 的序列化/反序列化问题

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 会通过访问器 (gettersetter) 实现类字段的定义。这与 @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. 降级 targetES2021 或更低版本
  1. 修改 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,以确保正确的序列化和监听。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值