コールバックとのやくそく

転職してすぐ入った今の案件のTypescriptはなぜかstrictモードが切られていたり、async/awaitもダメだったりする困ったちゃんです。コンパイルエラー?・・そんなものはない。

ということで非同期処理にはとにかくPromiseを使って書くわけですが、下のコード、どこがおかしいかわかりますか?

class Hello {
  private name: string = "";

  private remember(name: string): void {
    this.name = name;
  }

  public hi(name: string): void {
    new Promise<string>(resolve => {
      resolve(name);
    }).then(this.remember);
  }
}

const h = new Hello();
h.hi("john");

ちなみに以下のようなエラーが出ます。

$ ts-node hello.ts 
(node:10336) UnhandledPromiseRejectionWarning: TypeError: Cannot set property 'name' of undefined
    at Hello.remember (略)
(node:10336) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:10336) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

this.rememberの中にあるthis.nameで、thisが見つかっていませんね。

このエラー、関数オブジェクトを直接渡さないで無名関数でthen()を書いてたら出ないので「不思議だなー」と思ってしばらく放置してました。

でも、そういえばJavascriptって `function(){}` と `()=>{}` でthisの扱いが違うんですよね。関数オブジェクトを渡した時は前者の扱いで、うまくthisがバインドされないんでしょう。

なので、このエラーは以下のどちらかで解消されます。

(略).then(this.remember.bind(this));
(略).then(name => this.remember(name))

まあ、この例だとエラーが解消されたところで何も表示されないんですが。

こういうエラーに引っかかったら小さなコードを書いて再現してみるのも楽しいですね。

略してないのも置いておきます。それでは。

class Hello {
  private name: string = "";

  private remember(name: string): void {
    this.name = name;
  }

  public hi(name: string): void {
    new Promise<string>(resolve => {
      resolve(name);
    }).then(this.remember.bind(this));
  }
}

const h = new Hello();
h.hi("john");

この記事が気に入ったらサポートをしてみませんか?