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
になります。
@types/node
の型定義: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/010a8de/types/node/timers.d.ts#L73-L76- TypeScriptの
lib.dom.d.ts
の型定義: https://github.com/microsoft/TypeScript/blob/3431912/lib/lib.dom.d.ts#L16739
解決方法
1. setInterval()
を使う箇所で window.setInterval()
とする
window
オブジェクトにある setInterval()
の返り値の型は number
となっています。なので window.setInterval()
が使える環境であれば window.setInterval()
と書き換えると解決できます。
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ではハマる可能性が高いので気をつけましょう。