TypeScript - sử dụng đúng phiên bản setTimeout (nút so với cửa sổ)


115

Tôi đang tiến hành nâng cấp một số mã TypeScript cũ để sử dụng phiên bản trình biên dịch mới nhất và tôi đang gặp sự cố khi gọi tới setTimeout. Mã dự kiến ​​sẽ gọi setTimeouthàm của trình duyệt trả về một số:

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

Tuy nhiên, thay vào đó, trình biên dịch đang giải quyết vấn đề này cho việc triển khai nút, nó trả về một NodeJS.Timer:

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

Mã này không chạy trong nút, nhưng các kiểu gõ nút đang được kéo vào như một sự phụ thuộc vào một thứ khác (không chắc chắn là gì).

Làm cách nào để hướng dẫn trình biên dịch chọn phiên bản setTimeoutmà tôi muốn?

Đây là mã được đề cập:

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

Điều này tạo ra lỗi trình biên dịch:

TS2322: Không thể gán loại 'Bộ hẹn giờ' cho loại 'số'.


Bạn có loại: ["node"] trong tsconfig.json của mình không? Xem stackoverflow.com/questions/42940954/…
koe

@koe Không, tôi không có tùy chọn loại: ["node"] trong tệp tsconfig. Nhưng các loại nút đang được kéo vào như một sự phụ thuộc npm vào một thứ khác.
Kevin Tighe

1
Bạn cũng có thể xác định rõ ràng "loại" trong tsconfig.json - khi bạn bỏ qua "nút", nó không được sử dụng trong biên dịch. ví dụ: "loại": ["jQuery"]
koe

1
Điều đáng ngạc nhiên là câu trả lời của @koe (sử dụng tùy chọn "loại") không có bất kỳ phiếu bầu nào, là câu trả lời đúng duy nhất.
Egor Nepomnyaschih

@ KevinTighe's typeskhông bao gồm nodenhưng setTimeoutvẫn nhận được loại Node hơn là loại trình duyệt của nó. typesgiá trị mặc định cho tất cả các loại trong node_modules/@types, như được giải thích trong typescriptlang.org/tsconfig#types , nhưng ngay cả khi bạn làmtypeskhông bao gồm "node", tại sao setTimeoutvẫn nhận được loại Node của nó và làm thế nào bạn có thể nhận được các loại trình duyệt? Giải pháp của @ Axke là một chút hack, về cơ bản nói rằng nó trả lại những gì nó trả về. TypeScript vẫn có thể tìm sai kiểu, nhưng ít nhất nó sẽ luôn sai.
Denis Howe

Câu trả lời:


88

Một giải pháp khác không ảnh hưởng đến khai báo biến:

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

Ngoài ra, có thể sử dụng windowđối tượng một cách rõ ràng mà không cần any:

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

25
Tôi nghĩ cái kia ( window.setTimeout) phải là câu trả lời chính xác cho câu hỏi này vì nó là giải pháp rõ ràng nhất.
amik

5
Nếu bạn đang sử dụng anytype, bạn không thực sự đưa ra câu trả lời cho TypeScript.
S ..

tương tự như vậy, numberkiểu sẽ dẫn đến các lỗi lint cụ thể của TypeScript, vì setTimeouthàm yêu cầu nhiều hơn thế.
S ..

2
window.setTimeoutcó thể gây ra sự cố với các khuôn khổ kiểm tra đơn vị (node.js). Giải pháp tốt nhất là sử dụng let n: NodeJS.Timeoutn = setTimeout.
cchamberlain

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

clearTimeout(timer);

Bằng cách sử dụng, ReturnType<fn>bạn đang độc lập với nền tảng. Bạn sẽ không bị buộc phải sử dụng anycũng không window.setTimeoutsẽ phá vỡ nếu bạn chạy các mã (server-side trang trả lại ví dụ.) Không có máy chủ nodeJS.


Tin tốt, điều này cũng tương thích với Deno!


10
Tôi hiểu rằng đây là câu trả lời đúng và phải là câu được chấp nhận, vì nó cung cấp định nghĩa loại phù hợp cho mọi nền tảng hỗ trợ setTimeout/ clearTimeoutvà không sử dụng any.
afenster

12
Đây là giải pháp nếu bạn đang viết một thư viện chạy trên cả NodeJS và trình duyệt.
yqlim

Loại trả lại là NodeJS.Timeoutnếu sử dụng setTimeouttrực tiếp và numbernếu sử dụng window.setTimeout. Không cần thiết phải sử dụng ReturnType.
cchamberlain

@cchamberlain Bạn cần nó khi chạy setTimeouthàm và mong đợi kết quả của nó được lưu trữ trong biến. Hãy tự mình thử sức trong sân chơi của TS.
Akxe

Đối với OP và tôi, TypeScript bị loại setTimeoutsai (vì lý do không ai có thể giải thích) nhưng ít nhất giải pháp này sẽ che giấu điều đó theo cách tốt hơn một chút so với việc chỉ sử dụng any.
Denis Howe

15

Tôi đoán nó phụ thuộc vào nơi bạn sẽ chạy mã của mình.

Nếu mục tiêu thời gian chạy của bạn là Node JS phía máy chủ, hãy sử dụng:

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

Nếu mục tiêu thời gian chạy của bạn là một trình duyệt, hãy sử dụng:

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

5

Điều này có thể sẽ hoạt động với các phiên bản cũ hơn, nhưng với phiên bản TypeScript ^3.5.3và phiên bản Node.js ^10.15.3, bạn sẽ có thể nhập các chức năng dành riêng cho Node từ mô-đun Timers , tức là:

import { setTimeout } from 'timers';

Điều đó sẽ trả về một phiên bản của loại TimeoutNodeJS.Timeout mà bạn có thể chuyển đến clearTimeout:

import { clearTimeout, setTimeout } from 'timers';

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

clearTimeout(timeout);

1
Tương tự, nếu bạn muốn phiên bản trình duyệt của setTimeout, một cái gì đó giống như const { setTimeout } = windowsẽ xóa những lỗi đó.
Jack Steam

4

Tôi gặp phải vấn đề tương tự và cách giải quyết mà nhóm chúng tôi quyết định sử dụng, chỉ là sử dụng "bất kỳ" cho loại bộ hẹn giờ. Ví dụ:

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

Nó sẽ hoạt động với cả việc triển khai các phương thức setTimeout / setInterval / clearTimeout / clearInterval.


2
Vâng, điều đó có hiệu quả. Tôi cũng nhận ra rằng tôi có thể chỉ định phương thức trên đối tượng window trực tiếp: window.setTimeout (...). Không chắc đó có phải là cách tốt nhất để đi hay không nhưng tôi sẽ gắn bó với nó ngay bây giờ.
Kevin Tighe

1
Bạn có thể nhập không gian tên NodeJS đúng cách trong bảng chữ, hãy xem câu trả lời này .
hlovdal

Để thực sự trả lời câu hỏi ("làm cách nào để hướng dẫn trình biên dịch chọn phiên bản tôi muốn"), bạn có thể sử dụng window.setTimeout () thay thế, như @dhilt đã trả lời bên dưới.
Anson VanDoren

window.setTimeoutcó thể không hoạt động với các khuôn khổ kiểm tra đơn vị. Có một loại có thể được sử dụng ở đây .. Của nó NodeJS.Timeout. Bạn có thể nghĩ rằng bạn không ở trong môi trường nút nhưng tôi có tin tức cho bạn: Webpack / TypeScript, v.v. đang thực thi node.js.
cchamberlain

1
  • Nếu bạn muốn có giải pháp thực sự cho bản đánh chữ về bộ định thời thì ở đây chúng ta hãy:

    Lỗi trả lại là loại 'số' nó không phải là Hẹn giờ hay bất cứ thứ gì khác.

    Đây là giải pháp cho phiên bản typecripts ~> 2.7:

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

Bây giờ chúng ta đã sửa tất cả, chỉ cần khai báo như thế này:

 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;
         }

     ...
     }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.