TypeScript-setTimeoutの正しいバージョンを使用(ノードとウィンドウ)


111

私はいくつかの古いTypeScriptコードを最新のコンパイラバージョンを使用するようにアップグレードしていますが、への呼び出しで問題が発生していますsetTimeout。このコードはsetTimeout、数値を返すブラウザの関数を呼び出すことを想定しています。

setTimeout(handler: (...args: any[]) => void, timeout: number): number;

ただし、コンパイラーはこれを代わりにノード実装に解決し、NodeJS.Timerを返します。

setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;

このコードはノードでは実行されませんが、ノードのタイピングは他のものへの依存関係として取り込まれます(不明)。

setTimeout必要なバージョンを選択するようにコンパイラーに指示するにはどうすればよいですか?

問題のコードは次のとおりです。

let n: number;
n = setTimeout(function () { /* snip */  }, 500);

これにより、コンパイラエラーが発生します。

TS2322:タイプ 'Timer'はタイプ 'number'に割り当てることができません。


tsconfig.jsonにtypes:["node"]がありますか?stackoverflow.com/questions/42940954/…を
koe

@koeいいえ、tsconfigファイルにtypes:["node"]オプションがありません。しかし、ノードタイプは他のものへのnpm依存関係として取り込まれています。
Kevin Tighe 2017

1
また、tsconfig.jsonで「タイプ」を明示的に定義することもできます。「ノード」を省略すると、コンパイルでは使用されません。例 "types":["jQuery"]
koe

1
@koe( "types"オプションを使用)の回答に投票権がなく、唯一の正しい回答であるのは驚くべきことです。
Egor Nepomnyaschih

回答:


87

変数宣言に影響を与えない別の回避策:

let n: number;
n = <any>setTimeout(function () { /* snip */  }, 500);

また、次のようwindowにせずにオブジェクトを明示的に使用できるはずですany

let n: number;
n = window.setTimeout(function () { /* snip */  }, 500);

25
もう1つ(window.setTimeout)が最も明確な解決策であるため、この質問に対する正しい答えになるはずです。
amik 2018年

5
anyタイプを使用している場合、TypeScriptの答えを実際に提供しているわけではありません。
S ..

同様に、関数はそれ以上のことを必要とするため、number型はTypeScript固有のlintエラーを引き起こしsetTimeoutます。
S ..

1
window.setTimeout単体テストフレームワーク(node.js)で問題が発生する可能性があります。最良の解決策は、let n: NodeJS.Timeoutおよびを使用することn = setTimeoutです。
チェンバレン

102
let timer: ReturnType<typeof setTimeout> = setTimeout(() => { ... });

clearTimeout(timer);

を使用ReturnType<fn>することにより、プラットフォームからの独立性を得ることができます。あなたは使用するように強制されることはありませんanywindow.setTimeoutそれはなりますが、コードなしnodeJSサーバー(例えば、サーバー側レンダリングされたページ)を実行する場合破ります。


嬉しいことに、これはDenoにも対応しています!


9
これは正しい答えであり、受け入れられるべきであると私は理解しています。これは、setTimeout/ clearTimeoutをサポートし、使用しないすべてのプラットフォームに正しい型定義を提供するためanyです。
afenster

11
これは、NodeJSとブラウザーの両方で実行されるライブラリーを作成する場合の解決策です。
yqlim

戻り値の型はNodeJS.TimeoutsetTimeout直接使用する場合とを使用するnumber場合window.setTimeoutです。を使用する必要はありませんReturnType
チェンバレン

@cchamberlain setTimeout関数を実行し、その結果が変数に格納されることを期待しているときに必要になります。TSプレイグラウンドで自分で試してみてください。
Akxe

14

コードをどこで実行するかによります。

ランタイムターゲットがサーバー側のノードJSの場合は、次を使用します。

let timeout: NodeJS.Timeout;
global.clearTimeout(timeout);

ランタイムターゲットがブラウザの場合は、次を使用します。

let timeout: number;
window.clearTimeout(timeout);

4

私は同じ問題に直面し、私たちのチームが使用することを決めた回避策は、タイマータイプに「any」を使用することでした。例えば:

let n: any;
n = setTimeout(function () { /* snip */  }, 500);

setTimeout / setInterval / clearTimeout / clearIntervalメソッドの両方の実装で動作します。


2
ええ、それはうまくいきます。また、ウィンドウオブジェクトに直接メソッドを指定できることにも気づきました:window.setTimeout(...)。それが最善の方法であるかどうかはわかりませんが、とりあえずそれを使います。
Kevin Tighe 2017

1
NodeJS名前空間をtypescriptに適切にインポートできますこの回答を参照してください。
hlovdal

実際に質問に答えるには(「コンパイラーに必要なバージョンを選択するように指示するにはどうすればよいですか?」)、代わりにwindow.setTimeout()を使用できます。
アンソンヴァンドーレン

window.setTimeout単体テストフレームワークでは動作しない可能性があります。ここで使えるタイプがありますNodeJS.Timeout。あなたはあなたがノード環境にいないと思うかもしれませんが、私はあなたにニュースを持っています:Webpack / TypeScriptなどがnode.jsを実行しています。
チェンバレン

4

これは古いバージョンでも動作する可能性がありますが、TypeScriptバージョン^3.5.3とNode.jsバージョン^10.15.3では、タイマーモジュールからノード固有の関数をインポートできるはずです。

import { setTimeout } from 'timers';

それはあなたが渡すことができるタイプのタイムアウトのインスタンスを返します:NodeJS.TimeoutclearTimeout

import { clearTimeout, setTimeout } from 'timers';

const timeout: NodeJS.Timeout = setTimeout(function () { /* snip */  }, 500);

clearTimeout(timeout);

1
同様に、ブラウザバージョンのが必要な場合はsetTimeout、のような const { setTimeout } = windowものでこれらのエラーが解消されます。
Jack Steam

1
  • ここでタイマーに関するタイプスクリプトの実際の解決策が必要な場合は、次のようにします。

    バグは戻り値型 'number'にあり、Timerやその他のものではありません。

    これはtypescriptsバージョン〜2.7以上のソリューション用です:

export type Tick = null | number | NodeJS.Timer;

ここですべてを修正し、次のように宣言します。

 import { Tick } from "../../globals/types";

 export enum TIMER {
    INTERVAL = "INTERVAL",
    TIMEOUT = "TIMEOUT", 
 };

 interface TimerStateI {
   timeInterval: number;
 }

 interface TimerI: TimerStateI {
   type: string;
   autoStart: boolean;
   isStarted () : bool;
 }

     class myTimer extends React.Component<TimerI, TimerStateI > {

          private myTimer: Tick = null;
          private myType: string = TIMER.INTERVAL;
          private started: boll = false;

          constructor(args){
             super(args);
             this.setState({timeInterval: args.timeInterval});

             if (args.autoStart === true){
               this.startTimer();
             }
          }

          private myTick = () => {
            console.log("Tick");
          }    

          private startTimer = () => {

            if (this.myType === TIMER.INTERVAL) {
              this.myTimer = setInterval(this.myTick, this.timeInterval);
              this.started = true;
            } else if (this.myType === TIMER.TIMEOUT) {
              this.myTimer = setTimeout(this.myTick, this.timeInterval);
              this.started = true;
            }

          }

         private isStarted () : bool {
           return this.started;
         }

     ...
     }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.