【问题标题】:Property does not exist on union type on Phaser with TypeScript使用 TypeScript 的 Phaser 上的联合类型上不存在属性
【发布时间】:2021-02-25 17:32:31
【问题描述】:

我一直在关注本教程 https://learn.yorkcs.com/2019/02/07/build-a-space-shooter-with-phaser-3-3/ 来使用 Phaser 3 制作游戏,但由于我想在线部署它们,我正在转换代码以与 TypeScript 一起使用,因为我正在通过 Ionic 5 应用程序进行准备。在教程中,我应该设置玩家精灵的速度。为清楚起见,我必须创建两个类,Entities.js(我创建为entities.ts)和Player.js(我将其制成player.ts)。实体应该是Phaser.GameObjects.Sprite的扩展,玩家应该是实体,扩展实体类。到目前为止,除了设置玩家速度的部分外,我一切正常。

这是我的entities.ts

class Entity extends Phaser.GameObjects.Sprite {
  constructor(scene, x, y, key, type) {
    super(scene, x, y, key);

    this.scene = scene;
    this.scene.add.existing(this);
    this.scene.physics.world.enableBody(this, 0);
    this.setData('type', type);
    this.setData('isDead', false);
  }
}

这是我的player.ts

class Player extends Entity {
  constructor(scene, x, y, key) {
    super(scene, x, y, key, 'Player');

    this.setData('speed', 200);
    this.play('sprPlayer');
  }

  moveUp() {
    this.body.velocity.y = -this.getData('speed');
  }

  moveDown() {
    this.body.velocity.y = this.getData('speed');
  }

  moveLeft() {
    this.body.velocity.x = -this.getData('speed');
  }

  moveRight() {
    this.body.velocity.x = this.getData('speed');
  }

  update() {
    this.body.setVelocity(0, 0);
  }
}

一旦我写了this.body.setVelocity(0, 0)这一行,我就会得到一个错误:Property 'setVelocity' does not exist on type 'Body | StaticBody | BodyType'. Property 'setVelocity' does not exist on type 'StaticBody'。显然,精灵的主体可用于BodyStaticBodyBodyType 对象。查看文档,Bodyhttps://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.Body.html 允许 setVelocity 函数发生,而 StaticBody 一个 https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.StaticBody.html 不允许。

TypeScript 是否期望每种可能的类型都支持要使用的函数?如果是这样,我有没有办法指定我正在使用的body 的类型?我尝试解析无济于事。

现在,我认为可能有一种方法可以指定我希望在纯 JavaScript https://uptoskill.com/ionic-react-javascript/ 中开发的 Ionic,但不诉诸于此,有没有一种方法可以指定我希望在我的函数中使用联合中的哪种类型电话?请告诉我,感谢您的帮助。

【问题讨论】:

  • 请考虑修改此处的代码以构成一个独立的minimal reproducible example,适合放入像The TypeScript Playground 这样的独立IDE,和/或指向演示该问题的Web IDE 的链接。现在有人要么必须花费时间/精力在他们自己的环境中进行设置,要么给你一个他们没有测试过的答案。祝你好运!
  • 我将尝试重现此内容并使用 github repo 链接进行评论
  • 很遗憾,GitHub 存储库不是 Web IDE。考虑类似代码沙盒、TS Playground、stackblitz 等。这样做的目的是减少某人重现您的问题所需的工作量。另请注意,您应该使示例 minimal;取出与您遇到的问题无关的所有内容。祝你好运!
  • 我的意思是那很好,我可以查一下。但是如果我找不到一个以你描述的方式运行但对于 Ionic 的在线工具,那么它必须是一个 repo。
  • 当然,也许有人可以用它来帮助你,但我不能承诺在我自己的环境中安装一个 repo 来回答一个 SO 问题。您的问题带有 ionic-framework 标记,因此也许有人已经设置了此环境并对其有所了解。不过,我怀疑这与 ionic 的关系不大,而与 TypeScript 中的区分联合类型有关……而且您可以使用相关类/类型的 toy 版本重现您的问题,而无需需要纯 TypeScript 以外的任何东西。

标签: javascript angular typescript ionic-framework phaser-framework


【解决方案1】:

错误消息表明您的播放器主体是'Body | StaticBody | BodyType' 这些类型之一,但 StaticBody 没有setVelocity 方法。 Typescript 有 typeguards 的概念来处理这种情况,您可以使用具有不同成员的联合类型。

这里的解决方案是检查 this.body 是否有 setVolicity 函数。

update() {
    // when true typescript know it is not a StaticBody
    if ("setVelocity" in this.body)
    this.body.setVelocity(0, 0);
  }

您还可以定义一个自定义类型保护函数并在 if 语句中使用它,如下所示:

//custom typeguard function with the return type 'body is Body'    
function isBody(body: Body | StaticBody): body is Body {
  return (body as Body).setVelocity !== undefined;
}

if (isBody(this.body)) {
  this.body.setVelocity(5); 
}

【讨论】:

  • 虽然我看到了解决方案的意义,但它似乎不起作用。 typescriptlang.org/play?#code/…
  • 不幸的是,我的第一个带有属性访问器类型保护的示例似乎不起作用。我已经更新了 anwser,它说明了 in 运算符和自定义类型保护功能。
【解决方案2】:

正如 jcalz 所解释的,答案是测试所讨论的对象是否是包含要调用的函数的类的实例。换句话说,确保我们希望使用Body 而不是StaticBody。这可以通过简单地检查对象中是否存在函数来完成:

if('setVelocity' in this.body) {
  this.body.setVelocity(0, 0);
}

更具体地说,我们可以通过以下方式检查对象是否是预期对象的实例:

if(this.body instanceof Phaser.Physics.Arcade.Body) {
  this.body.setVelocity(0, 0);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-19
    • 2023-04-02
    • 2018-08-17
    • 1970-01-01
    • 2023-02-06
    • 2020-09-27
    • 2019-06-28
    相关资源
    最近更新 更多