TypeScript - 올바른 버전의 setTimeout 사용(노드와 창)
최신 버전의 컴파일러를 사용하기 위해 오래된 TypeScript 코드를 업그레이드하고 있는데 호출에 문제가 있습니다.setTimeout
코드에서는 브라우저의 콜을 상정하고 있습니다.setTimeout
숫자를 반환하는 함수:
setTimeout(handler: (...args: any[]) => void, timeout: number): number;
단, 컴파일러는 노드 구현으로 이 문제를 해결하고 NodeJs를 반환합니다.타이머:
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;
이 코드는 노드에서는 실행되지 않지만 노드 타입은 다른 것에 대한 종속성(무엇에 대한 의존성)으로 인식되고 있습니다.
컴파일러에 명령어 버전 선택을 지시하려면 어떻게 해야 합니까?setTimeout
내가 원하는 거?
문제의 코드는 다음과 같습니다.
let n: number;
n = setTimeout(function () { /* snip */ }, 500);
이로 인해 컴파일러 오류가 발생합니다.
TS2322: '타이머' 유형은 '번호' 유형에 할당할 수 없습니다.
let timer: ReturnType<typeof setTimeout> = setTimeout(() => { ... });
clearTimeout(timer);
사용방법ReturnType<fn>
플랫폼으로부터 독립하는 것입니다.둘 다 사용하지 않아도 됩니다.any
도 아니다window.setTimeout
노드상에서 코드를 실행하면, 파손됩니다.JS 서버(예: 서버측 렌더링 페이지).
좋은 소식입니다, 이것도 Deno에 대응하고 있습니다!
2021년 갱신
Akxe의 답변에 따르면ReturnType<Type>
타입스크립트 2.3에 도입된 기술:
let n: ReturnType<typeof setTimeout>;
n = setTimeout(cb, 500);
그것은 좋고 명시적인 캐스팅보다 선호되는 것처럼 보인다.단, 이 경우 n의 결과 유형은 NodeJS입니다.Timeout"은 다음과 같이 사용할 수 있습니다.
let n: NodeJS.Timeout;
n = setTimeout(cb, 500);
Return Type/Node JS의 유일한 문제타임아웃 어프로치란 브라우저 고유의 환경에서 수치 조작을 실시하려면 여전히 캐스팅이 필요하다는 것입니다.
if ((n as unknown as number) % 2 === 0) {
clearTimeout(n);
}
원답
변수 선언에 영향을 주지 않는 회피책:
let n: number;
n = setTimeout(function () { /* snip */ }, 500) as unknown as number;
또한 브라우저 고유의 환경에서는window
캐스팅이 없는 객체:
let n: number;
n = window.setTimeout(function () { /* snip */ }, 500);
어디서 코드를 실행하느냐에 따라 다르겠죠.
런타임 대상이 서버 측 노드 JS인 경우 다음을 사용합니다.
let timeout: NodeJS.Timeout;
global.clearTimeout(timeout);
런타임 대상이 브라우저인 경우 다음을 사용합니다.
let timeout: number;
window.clearTimeout(timeout);
이것은 나에게 완벽하게 잘 작동한다.
type Timer = ReturnType<typeof setTimeout>
const timer: Timer = setTimeout(() => {}, 1000)
이 기능은 이전 버전에서는 작동하지만 TypeScript 버전에서는 작동합니다.^3.5.3
및 Node.js 버전^10.15.3
Timers 모듈에서 노드 고유의 기능을 Import할 수 있습니다.즉, 다음과 같습니다.
import { setTimeout } from 'timers';
그러면 Timeout of type의 인스턴스가 반환됩니다.NodeJS.Timeout
넘겨줄 수 있는clearTimeout
:
import { clearTimeout, setTimeout } from 'timers';
const timeout: NodeJS.Timeout = setTimeout(function () { /* snip */ }, 500);
clearTimeout(timeout);
또, 다음의 사양에 대해서도 언급하고 싶다.NodeJS.Timeout
포함한다[Symbol.toPrimitive](): number
:
interface Timeout extends Timer {
/**
* If true, the `Timeout` object will keep the Node.js event loop active.
* @since v11.0.0
*/
hasRef(): boolean;
/**
* Sets the timer's start time to the current time, and reschedules the timer to
* call its callback at the previously specified duration adjusted to the current
* time. This is useful for refreshing a timer without allocating a new
* JavaScript object.
*
* Using this on a timer that has already called its callback will reactivate the
* timer.
* @since v10.2.0
* @return a reference to `timeout`
*/
refresh(): this;
[Symbol.toPrimitive](): number;
}
또한 호환성을 위해 노드의 다른 타임아웃 API는 플레인 정수 ID에서 정상적으로 작동하므로 개체를 수락할 필요가 없습니다.오브젝트는 "서버"측에서 사용되며 프로세스 활성 및 가비지 수집을 보다 세밀하게 제어할 수 있습니다.예를 들어 다음과 같습니다.
function clearTimeout(timeoutId: NodeJS.Timeout | string | number | undefined): void;
, ,, 음, 음, 음, 다, 다, 다, 다, 다, cast, cast, cast, cast, cast, cast, cast, cast, this, this, this, cast, this, ,, cast, cast, cast, on, this, this, setTimeout
★★★★★★★★★★★★★★★★★」setInterval
:
let timeoutId: number | undefined;
timeoutId = Number(setTimeout(callback, ms));
function clear() {
clearTimeout(timeoutId);
}
어떤 API와도 충돌하지 않습니다.다만, 나중에 다른 API 계약에 대한 초기값으로 의존할 필요가 있는지 여부에 대해서는 문제가 되지 않습니다.
setInterval
window
쓸 도 있어요.
let timerId: number = setInterval((()=>{
this.populateGrid(true)
}) as TimerHandler, 5*1000)
}
나는 이 문제를 세팅으로 해결했다.
tsconfig.json:
{
"compilerOptions": {
"skipLibCheck": true,
}
}
그리고 .d.ts를 만듭니다.
*.d.ts:
declare namespace NodeJS {
type Timeout = number;
type Timer = number;
}
타이프 스크립트버전 4.2.3
리액트를 사용하고 있었는데, 같은 문제가 있어서 다음과 같이 해결했습니다.
import React, { useRef, useState, useEffect} from 'react';
import { Alert } from '../types/alerts';
const AlertComponent: React.FC<{alert: Alert}> = ({alert}) => {
const intervalRef = useRef<NodeJS.Timeout>();
const [count, setCount] = useState(alert.timeLimit)
useEffect(() => {
intervalRef.current = setInterval(
() => {setCount((count) => count - 1)},
1000
)
return () => {
clearInterval(intervalRef.current as NodeJS.Timeout)
}
}, [])
return (
<p>{count}</p>
)
}
export default AlertComponent;
에 useEffect()가 있습니다.clearInterval(intervalRef.current as NodeJS.Timeout)
clear" "를 명시적으로 때문입니다.NodeJ는 NodeJ를 사용합니다.[ Timeout ] | undefined ]미정의입니다.
RTL을 사용하여 Counter 앱을 테스트하고 있었습니다.구체적으로는 카운트가 15가 되면 삭제되는 요소를 테스트하고 있었습니다.테스트 실행 후 컴포넌트가 파기되기 때문에 setTimeout은 이후에도 계속 실행되며 React는 마운트 해제된 컴포넌트에 대해 상태 업데이트를 수행할 수 없다는 오류가 발생합니다.따라서 dhilt의 답변을 바탕으로 다음과 같이 useEffect 청소 기능을 수정할 수 있었습니다.
const [count, setCount] = useState(initialCount);
const [bigSize, setBigSize] = useState(initialCount >= 15);
useEffect(() => {
let id: NodeJS.Timeout;
if(count >= 15) {
id = setTimeout(() => setBigSize(true), 300);
}
return function cleanup() {
clearTimeout(id);
}
});
테스트 스위트는 다음과 같습니다.
describe('when the incrementor changes to 5 and "add" button is clicked', () => {
beforeEach(async () => {
userEvent.type(screen.getByLabelText(/Incrementor/), '{selectall}5');
userEvent.click(screen.getByRole('button', {name: "Add to Counter"}));
await screen.findByText('Current Count: 15');
})
it('renders Current Count: 15', () => {
expect(screen.getByText('Current Count: 15')).toBeInTheDocument();
});
it('renders too big and will dissapear after 300ms',async() => {
await waitForElementToBeRemoved(() => screen.queryByText(/size: small/i))
});
})
TS2322: '타이머' 유형은 '번호' 유형에 할당할 수 없습니다.
심플한 솔루션
abc : any;
애초에
abc = setInterval 또는 abc = setTimeout
저도 같은 문제에 직면했고, 저희 팀이 사용하기로 결정한 회피책은 타이머 유형에 "임의"를 사용하는 것이었습니다.예:
let n: any;
n = setTimeout(function () { /* snip */ }, 500);
set Timeout/set의 양쪽 구현에서 동작합니다.인터벌/clearTimeout/clear인터벌 메서드
언급URL : https://stackoverflow.com/questions/45802988/typescript-use-correct-version-of-settimeout-node-vs-window
'programing' 카테고리의 다른 글
구문 분석 오류: 파일 '.../tsconfig'를 읽을 수 없습니다.json'.eslint (0) | 2023.04.06 |
---|---|
Angular.js - ng-pattern이 $비활성일 경우 ng-change가 실행되지 않음 (0) | 2023.04.06 |
Word Press vs Expression Engine: EE는 가격 대비 가치가 있습니까? (0) | 2023.04.01 |
영숫자가 아닌 문자를 삭제하려면 어떻게 해야 합니까? (0) | 2023.04.01 |
알 수 없는 구조로 JSON을 디코딩합니다. (0) | 2023.04.01 |