最近在写一个基于 Vite + Vitest + React + Typescript
的放置类游戏写到计时器的时候遇到一个类型检查的问题
简写代码如下
interface IFisherTimerAction {
(): void;
}
interface IFisherTimer {
/**
* 计时器要执行的action
*
* @type {IFisherTimerAction}
* @memberof IFisherTimer
*/
action: IFisherTimerAction;
/**
* 是否立即执行一次
* 默认开启
* @type {boolean}
* @memberof IFisherTimer
*/
fireImmediately?: boolean;
}
class Timer {
public timerId?: number;
public action: IFisherTimerAction;
public actionInterval?: number;
public fireImmediately: boolean;
constructor({ action, fireImmediately }: IFisherTimer) {
this.action = action;
this.fireImmediately = fireImmediately ?? true;
}
/**
* 开始执行计时器任务
*
* @param {number} actionInterval
* @memberof Timer
*/
public startTimer = (actionInterval: number) => {
this.actionInterval = actionInterval;
this.timerId && clearInterval(this.timerId);
this.timerId = setInterval(() => this.action(), actionInterval);
this.fireImmediately && this.action();
};
}
会报错:不能将类型 NodeJS.Timer
分配给类型 number
原因是因为项目使用了 Vitest
作为单元测试框架,会引入 NodeJS
的类型定义文件污染了本应该是浏览器端项目的全局类型
解决方案
使用 Typescript
的 ReturnType
封装一个 Timer
类型之后便不会报错。原理很简单,使用 ReturnType
来推断计时器 api 的类型
type Timer = ReturnType<typeof setTimeout>;
class Timer {
public timerId?: Timer;
...
public startTimer = (actionInterval: number) => {
...
this.timerId && clearInterval(this.timerId);
this.timerId = setInterval(() => this.action(), actionInterval);
...
};
}