Pracuję nad uaktualnieniem starego kodu TypeScript do najnowszej wersji kompilatora i mam problem z wywołaniem do setTimeout
. Kod oczekuje wywołania funkcji przeglądarki, setTimeout
która zwraca liczbę:
setTimeout(handler: (...args: any[]) => void, timeout: number): number;
Jednak kompilator zamiast tego rozwiązuje to na implementację węzła, która zwraca NodeJS.Timer:
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
Ten kod nie działa w węźle, ale typy węzłów są pobierane jako zależność od czegoś innego (nie wiem co).
Jak mogę poinstruować kompilator, aby wybrał wersję setTimeout
, której chcę?
Oto kod, o którym mowa:
let n: number;
n = setTimeout(function () { /* snip */ }, 500);
Powoduje to błąd kompilatora:
TS2322: Typu „Timer” nie można przypisać do typu „numer”.
typescript
settimeout
Kevin Tighe
źródło
źródło
types
nie obejmuje,node
alesetTimeout
nadal pobiera typ węzła, a nie typ przeglądarki.types
domyślnie do wszystkich typów wnode_modules/@types
, jak wyjaśniono w typescriptlang.org/tsconfig#types , ale nawet jeśli zrobić określićtypes
i nie obejmują"node"
, dlaczegosetTimeout
wciąż jej typ węzła i jak można uzyskać typ przeglądarki? Rozwiązanie @ Axke to trochę hack, mówiąc po prostu, że zwraca to, co zwraca. TypeScript może nadal znajdować niewłaściwy typ, ale przynajmniej będzie konsekwentnie błędny.Odpowiedzi:
Inne obejście, które nie ma wpływu na deklarację zmiennej:
let n: number; n = <any>setTimeout(function () { /* snip */ }, 500);
Powinno być również możliwe
window
jawne użycie obiektu bezany
:let n: number; n = window.setTimeout(function () { /* snip */ }, 500);
źródło
window.setTimeout
) powinna być poprawną odpowiedzią na to pytanie, ponieważ jest to najwyraźniejsze rozwiązanie.any
typu, tak naprawdę nie dajesz odpowiedzi TypeScript.number
typ prowadzi do błędów lint specyficznych dla języka TypeScript, ponieważsetTimeout
funkcja wymaga czegoś więcej.window.setTimeout
może powodować problemy z platformami testów jednostkowych (node.js). Najlepszym rozwiązaniem jest użycielet n: NodeJS.Timeout
in = setTimeout
.let timer: ReturnType<typeof setTimeout> = setTimeout(() => { ... }); clearTimeout(timer);
Korzystając z
ReturnType<fn>
niej uzyskujesz niezależność od platformy. Nie będzie zmuszony do korzystaniaany
aniwindow.setTimeout
który będzie złamać jeśli uruchomić kod żaden serwer nodeJS (np. Server-side wygenerowana strona).Dobra wiadomość, to jest również kompatybilne z Deno!
źródło
setTimeout
/clearTimeout
i której nie używaany
.NodeJS.Timeout
jeśli używaszsetTimeout
bezpośrednio inumber
jeśli używaszwindow.setTimeout
. Nie powinno używaćReturnType
.setTimeout
funkcję i oczekujesz, że jej wynik zostanie zapisany w zmiennej. Spróbuj sam w TS zabaw.setTimeout
błędu (z powodów, których nikt nie może wyjaśnić), ale przynajmniej to rozwiązanie powinno maskować to w nieco lepszy sposób niż samo użycieany
.Myślę, że zależy to od tego, gdzie będziesz uruchamiać swój kod.
Jeśli celem środowiska wykonawczego jest Node JS po stronie serwera, użyj:
let timeout: NodeJS.Timeout; global.clearTimeout(timeout);
Jeśli celem środowiska wykonawczego jest przeglądarka, użyj:
let timeout: number; window.clearTimeout(timeout);
źródło
Prawdopodobnie zadziała to ze starszymi wersjami, ale z wersją TypeScript
^3.5.3
i wersją Node.js^10.15.3
powinieneś być w stanie zaimportować funkcje specyficzne dla węzła z modułu Timers , tj .:import { setTimeout } from 'timers';
Że zwróci instancję Timeout typu
NodeJS.Timeout
, które można przekazać doclearTimeout
:import { clearTimeout, setTimeout } from 'timers'; const timeout: NodeJS.Timeout = setTimeout(function () { /* snip */ }, 500); clearTimeout(timeout);
źródło
setTimeout
, coś takiego jakconst { setTimeout } = window
usunie te błędy.Zmierzyłem się z tym samym problemem i rozwiązaniem, które nasz zespół zdecydował się zastosować, było po prostu użycie „any” dla typu timera. Na przykład:
let n: any; n = setTimeout(function () { /* snip */ }, 500);
Będzie działać z obiema implementacjami metod setTimeout / setInterval / clearTimeout / clearInterval.
źródło
window.setTimeout
może nie działać z platformami testów jednostkowych. Jest typ, którego można tu użyć ... JegoNodeJS.Timeout
. Możesz pomyśleć, że nie jesteś w środowisku węzłów, ale mam dla Ciebie wiadomość: Webpack / TypeScript itp. Wykonują node.js.Jeśli chcesz prawdziwego rozwiązania dla maszynopisu dotyczącego timerów, zaczynamy:
Błąd jest w zwracanym typie „liczba”, nie jest to Timer ani nic innego.
Dotyczy to rozwiązania dla maszynopisów w wersji ~> 2.7:
Teraz naprawiliśmy wszystko, po prostu zadeklaruj w ten sposób:
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; } ... }
źródło
Jeśli celem
setInterval
jestwindow
. Następnie możesz również zapisać go jakolet timerId: number = setInterval((()=>{ this.populateGrid(true) }) as TimerHandler, 5*1000) }
źródło