https://www.konosumi.net/entry/2019/05/26/150656

AngularのSPA(Single Page Application)のプログラムを書いてたら、以下の問題に遭遇しました。

内容としては**「Type 'Timer' is not assignable to type 'number'.」**というエラーメッセージが表示されます。 VSCode(Visual Studio Code)で関数の戻り値を確認すると、戻り値の型はNodeJS.Timerになってます。

私の場合は、Angularで「setTimeout()」を記述しただけです。なぜそれが「NodeJS.Timer」となってしまうのか気になったので、調べてみました。

次のstack overflowを見るとわかるのですが、「setTimeout()」を「window.setTimeout()」に変えると、戻り値は数値型で通用します。

// Another workaround that does not affect variable declaration:
let n: number;
n = <any>setTimeout(function () { /* snip */  }, 500);

// Also, it should be possible to use the window object explicitly without any:
let n: number;
n = window.setTimeout(function () { /* snip */  }, 500);

この仕様はMDNにも記載されており、「window.setTimeout()」のドキュメントを確認すると、確かに戻り値は数値型です。

戻り値 timeoutID は、setTimeout() を呼び出して作成したタイマーを識別する正の整数値です。

引用:https://developer.mozilla.org/ja/docs/Web/API/WindowTimers/setTimeout

setTimeout()とwindow.setTimeout()の違い

ではなぜ「window.setTimeout()」にするとTypeScriptの戻り値の解釈が変わるのかと申しますと、これは「setTimeout()」との違いが関係するようです。

For JavaScript that does not run in a browser, the window object is not defined, so window.setTimeout() will fail. setTimeout() however, will work.

引用: https://stackoverflow.com/questions/20420429/what-the-difference-between-window-settimeout-and-settimeout

function myF() {
  function setTimeout(callback,seconds) {
    // call the native setTimeout function
    return window.setTimeout(callback,seconds*1000);
  }
  // call your own setTimeout function (with seconds instead of milliseconds)
  setTimeout(function() {console.log("hi"); },3);
}
myF();

要約すると「window.setTimeout()」が明示的にブラウザの「setTimeout()」を使うよう指示していることに対し、 単なる「setTimeout()」ではブラウザ外(例えばNode.jsのサーバーサイド)のJSや、自分たちで用意した関数も考慮されます。

その結果「setTimeout()」のTypeScriptにおける戻り値の型が、NodeJS.Timerになっているようです。

「window.」の省略について