I’m currently developing a multithreading library and have encountered an issue related to TypeScript enum comparisons within the Thread.execute()
method. The problem arises specifically when comparing the state property.
Here is snippet of the erroring code:
37. if(this.#state === State.INTERRUPTED) {
38. this.#reset()
39. break
40. }
The error:
TS2367: This comparison appears to be unintentional because the types State.RUNNING and State.INTERRUPTED have no overlap.
Here is the whole code:
1. import { ThrottleCallback, TransferData } from '../../types/core/Threads';
2. import ThreadInterface, { Mode, State } from '../../types/core/Thread';
3. import { HybridExecutor } from '../../types/core/Executor';
4. import { Task } from '../../types/partials/TaskPool';
5.
6. export default class Thread implements ThreadInterface {
7. #executor: HybridExecutor;
8.
9. #state: State = State.IDLE;
10.
11. #progress: number = 0;
12.
13. constructor(Executor: new() => HybridExecutor) {
14. this.#executor = new Executor();
15. }
16.
17. async execute(data: TransferData, mode: Mode = Mode.SEQUENTIAL): Promise<any[]> {
18. if (this.#state === State.RUNNING) await this.#waitForThreadIdle();
19.
20. this.#state = State.RUNNING;
21.
22. const responses: any[] = data?.responses ?? [];
23.
24. const tasks: Task[] = data.pool.pool;
25.
26. while (data.pool.length && this.#state === State.RUNNING) {
27. // Get the next task & remove it from the pool
28. const task: Task = tasks.splice(0, 1).at(0)!;
29.
30. // Sequential mode: set the message to the response of the previous task (if exists)
31. if (mode === Mode.SEQUENTIAL) task.message = task?.message ?? responses.at(-1);
32.
33. // If throttle is set, wait for its completion. If it fails, terminate the thread
34. if (data.throttle) await this.#waitForThrottleSuccess(data.throttle).catch();
35.
36. // Check if the thread has been interrupted
37. if (this.#state === State.INTERRUPTED) {
38. this.#reset();
39. break;
40. }
41.
42. // Run the task and get the response
43. const response = await this.#executor.run(task.method, task.message);
44.
45. // Check if the response is an error and gracefully terminate the thread
46. if (response?.error) {
47. console.error(response.error);
48. break;
49. }
50.
51. // Save the response
52. responses[task.index!] = response;
53.
54. // Execute the step callback
55. const progress: number = responses.filter((response) => response !== undefined).length / data.poolSize;
56. this.#progress = progress;
57. data.step?.(responses[task.index!], progress * 100);
58. }
59.
60. this.#reset();
61.
62. return responses;
63. }
64.
65. terminate(): void {
66. this.#state = State.IDLE;
67. }
68.
69. #reset(): void {
70. this.#state = State.IDLE;
71. this.#progress = 0;
72. this.#executor.terminate();
73. }
74.
75. #waitForThreadIdle = async (): Promise<void> => {
76. return await new Promise<void>(async (resolve): Promise<void> => {
77. const interval = async () => {
78. if (this.#state === State.IDLE) return resolve();
79. else requestAnimationFrame(interval);
80. };
81.
82. interval().then();
83. });
84. };
85.
86. #waitForThrottleSuccess = async (throttle: ThrottleCallback): Promise<void> => {
87. return await new Promise<void>(async (resolve) => {
88. const interval = async () => {
89.
90. const throttleResult: boolean = await Promise.resolve(throttle()).catch((e: Error) => {
91. this.#state = State.INTERRUPTED;
92. throw `Throttle error: ${e}`;
93. });
94.
95. if (throttleResult) return resolve();
96. else requestAnimationFrame(interval);
97. };
98.
99. interval().then();
100. });
101. };
102.
103. get state(): State {
104. return this.#state;
105. }
106.
107. get progress(): number {
108. return this.#progress;
109. }
110. }
Here is the enum
representing the different states:
export enum State {
IDLE = 'idle',
RUNNING = 'running',
INTERRUPTED = 'interrupted'
}
The only thing I noticed is that the error is somehow linked to the line 20 this.#state = State.RUNNING
. For example, if I change this assignment to this.#state = State.INTERRUPTED
, the error shifts to another comparison:
26. while (data.pool.length && this.#state === State.RUNNING) {
...
Thanks in advance <3
Fix the TS2367: This comparison appears to be unintentional because the types State.RUNNING and State.INTERRUPTED have no overlap.
error on line 37.