学ぶ、考える、書き出す。

学習し、自分なりに噛み砕いて、書き出すブログ。

TypeScriptでsetInterval()の型が合わない理由と解決方法

@types/node に依存した状態で以下のようなコードを書いたときに Type 'Timer' is not assignable to type 'number'. というエラーメッセージが出ます。

export class ExampleClass {
  intervalId: number;

  constructor() {
    this.intervalId = 0;
  }

  start() {
    this.intervalId = setInterval(() => {
      // do something
    }, 1000);
  }

  stop() {
    clearInterval(this.intervalId);
    this.intervalId = 0;
  }
}

原因

@types/node に依存している場合 setInterval() の返り値が NodeJS.Timer となるためです。@types/node に依存していなければ setInterval() の返り値は number になります。

解決方法

1. setInterval() を使う箇所で window.setInterval() とする

window オブジェクトにある setInterval() の返り値の型は number となっています。なので window.setInterval() が使える環境であれば window.setInterval() と書き換えると解決できます。

参考: setInterval - Type 'Timer' is not assignable to type 'number' · Issue #1053 · TypeStrong/atom-typescript

2. setInterval() の返り値を入れるプロパティの型を変更する

window.setInterval() と書き換える方法は、SSRをしているときには使えません。たとえばNext.jsを使っている場合にはエラーが出ると思われます。

この場合は以下のように intervalId の初期値に null を入れておいて、clearInterval() を実行するところで setInterval() の返り値が this.intervalId に入っているか確かめる方法があります。

export class ExampleClass {
  intervalId: NodeJS.Timer | null;

  constructor() {
    this.intervalId = null;
  }

  start() {
    this.intervalId = setInterval(() => {
      // do something
    }, 1000);
  }

  stop() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }

    this.intervalId = null;
  }
}

3. setInterval() 全体を Number() で囲む

关于typescript的定时器setInterval()坑_ollin2012的博客-CSDN博客_ts 定时器类型で紹介されている手法を多少改変して、setInterval() 全体を Number() で囲んで number 型にtype assertionする手法もあります。

export class ExampleClass {
  intervalId: number;

  constructor() {
    this.intervalId = 0;
  }

  start() {
    this.intervalId = Number(setInterval(() => {
      // do something
    }, 1000));
  }

  stop() {
    clearInterval(this.intervalId);
    this.intervalId = 0;
  }
}

まとめ

手癖のように intervalID が入るところで初期値として 0 を代入していましたが、TypeScriptではハマる可能性が高いので気をつけましょう。

記事を共有する

関連記事

  1. eslint-plugin-importによってVitestの設定ファイル上でエラーが発生する場合がある

    vitest と eslint-plugin-import に依存している環境では、vitest.config.ts内で vitest/config をインポートすると Unable to resolve path to module 'vitest/config'. eslint(import/no-unresolved) というエラーが出る場合があります。

  2. PreactとTypeScriptを使った環境でStorybookを使う方法

    Preact と TypeScript を使った環境で Storybook を使おうとしたら以下のエラーが出ました。

  3. Next.js + Vercel + microCMSなどを使ってほぼ無料でブログを運用する

    当ブログのシステム構成について紹介します。構成を真似することでほぼ無料(後述)でブログを運営できます。

  4. ブログ記事を投稿するためのフォームを作った

    はてなブログのMarkdownによる記事編集画面やesa - 自律的なチームのための情報共有サービスのように、本文の編集画面とリアルタイムプレビューが横並びになるような投稿フォームが個人的に好みです。