@byloth/core 2.0.0-rc.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +4087 -621
- package/dist/core.js.map +1 -1
- package/dist/core.umd.cjs +2 -2
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +17 -13
- package/src/core/types.ts +41 -0
- package/src/helpers.ts +11 -2
- package/src/index.ts +12 -9
- package/src/models/aggregators/aggregated-async-iterator.ts +920 -21
- package/src/models/aggregators/aggregated-iterator.ts +838 -22
- package/src/models/aggregators/reduced-iterator.ts +827 -11
- package/src/models/aggregators/types.ts +153 -10
- package/src/models/callbacks/callable-object.ts +42 -6
- package/src/models/callbacks/index.ts +2 -2
- package/src/models/callbacks/publisher.ts +160 -4
- package/src/models/callbacks/switchable-callback.ts +230 -23
- package/src/models/callbacks/types.ts +16 -0
- package/src/models/exceptions/core.ts +132 -3
- package/src/models/exceptions/index.ts +405 -13
- package/src/models/index.ts +4 -8
- package/src/models/iterators/smart-async-iterator.ts +827 -22
- package/src/models/iterators/smart-iterator.ts +755 -20
- package/src/models/iterators/types.ts +268 -9
- package/src/models/json/json-storage.ts +508 -110
- package/src/models/json/types.ts +10 -1
- package/src/models/promises/deferred-promise.ts +85 -5
- package/src/models/promises/index.ts +1 -3
- package/src/models/promises/smart-promise.ts +272 -4
- package/src/models/promises/timed-promise.ts +43 -1
- package/src/models/promises/types.ts +84 -2
- package/src/models/timers/clock.ts +109 -19
- package/src/models/timers/countdown.ts +176 -21
- package/src/models/timers/game-loop.ts +266 -0
- package/src/models/timers/index.ts +2 -1
- package/src/models/types.ts +6 -5
- package/src/utils/async.ts +43 -0
- package/src/utils/curve.ts +85 -0
- package/src/utils/date.ts +204 -10
- package/src/utils/dom.ts +16 -2
- package/src/utils/index.ts +3 -2
- package/src/utils/iterator.ts +200 -17
- package/src/utils/math.ts +55 -3
- package/src/utils/random.ts +139 -2
- package/src/utils/string.ts +11 -0
- package/src/models/game-loop.ts +0 -83
- package/src/models/promises/long-running-task.ts +0 -294
- package/src/models/promises/thenable.ts +0 -97
|
@@ -1,20 +1,60 @@
|
|
|
1
1
|
import { TimeUnit } from "../../utils/date.js";
|
|
2
|
-
import { RangeException, RuntimeException } from "../exceptions/index.js";
|
|
3
2
|
|
|
4
3
|
import Publisher from "../callbacks/publisher.js";
|
|
5
|
-
import
|
|
4
|
+
import { FatalErrorException, RangeException, RuntimeException } from "../exceptions/index.js";
|
|
5
|
+
import type { Callback } from "../types.js";
|
|
6
|
+
|
|
7
|
+
import GameLoop from "./game-loop.js";
|
|
6
8
|
|
|
7
9
|
interface ClockEventMap
|
|
8
10
|
{
|
|
9
11
|
start: () => void;
|
|
10
12
|
stop: () => void;
|
|
11
13
|
tick: (elapsedTime: number) => void;
|
|
14
|
+
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
[key: string]: Callback<any[], any>;
|
|
12
17
|
}
|
|
13
18
|
|
|
19
|
+
/**
|
|
20
|
+
* A class representing a clock.
|
|
21
|
+
*
|
|
22
|
+
* It can be started, stopped and, when running, it ticks at a specific frame rate.
|
|
23
|
+
* It's possible to subscribe to these events to receive notifications when they occur.
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* const clock = new Clock();
|
|
27
|
+
*
|
|
28
|
+
* clock.onStart(() => { console.log("The clock has started."); });
|
|
29
|
+
* clock.onTick((elapsedTime) => { console.log(`The clock has ticked at ${elapsedTime}ms.`); });
|
|
30
|
+
* clock.onStop(() => { console.log("The clock has stopped."); });
|
|
31
|
+
*
|
|
32
|
+
* clock.start();
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
14
35
|
export default class Clock extends GameLoop
|
|
15
36
|
{
|
|
16
|
-
|
|
17
|
-
|
|
37
|
+
/**
|
|
38
|
+
* The {@link Publisher} object that will be used to publish the events of the clock.
|
|
39
|
+
*/
|
|
40
|
+
protected override _publisher: Publisher<ClockEventMap>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Initializes a new instance of the {@link Clock} class.
|
|
44
|
+
*
|
|
45
|
+
* ---
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const clock = new Clock();
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* ---
|
|
53
|
+
*
|
|
54
|
+
* @param msIfNotBrowser
|
|
55
|
+
* The interval in milliseconds at which the clock will tick if the environment is not a browser.
|
|
56
|
+
* `TimeUnit.Second` by default.
|
|
57
|
+
*/
|
|
18
58
|
public constructor(msIfNotBrowser: number = TimeUnit.Second)
|
|
19
59
|
{
|
|
20
60
|
super((elapsedTime) => this._publisher.publish("tick", elapsedTime), msIfNotBrowser);
|
|
@@ -22,33 +62,83 @@ export default class Clock extends GameLoop
|
|
|
22
62
|
this._publisher = new Publisher();
|
|
23
63
|
}
|
|
24
64
|
|
|
25
|
-
|
|
65
|
+
/**
|
|
66
|
+
* Starts the execution of the clock.
|
|
67
|
+
*
|
|
68
|
+
* If the clock is already running, a {@link RuntimeException} will be thrown.
|
|
69
|
+
*
|
|
70
|
+
* ---
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* clock.onStart(() => { [...] }); // This callback will be executed.
|
|
75
|
+
* clock.start();
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* ---
|
|
79
|
+
*
|
|
80
|
+
* @param elapsedTime The elapsed time to set as default when the clock starts. Default is `0`.
|
|
81
|
+
*/
|
|
82
|
+
public override start(elapsedTime = 0): void
|
|
26
83
|
{
|
|
27
84
|
if (this._isRunning) { throw new RuntimeException("The clock has already been started."); }
|
|
28
85
|
|
|
29
|
-
|
|
86
|
+
this._startTime = performance.now() - elapsedTime;
|
|
87
|
+
this._start();
|
|
88
|
+
this._isRunning = true;
|
|
30
89
|
|
|
31
90
|
this._publisher.publish("start");
|
|
32
91
|
}
|
|
33
92
|
|
|
34
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Stops the execution of the clock.
|
|
95
|
+
*
|
|
96
|
+
* If the clock hasn't yet started, a {@link RuntimeException} will be thrown.
|
|
97
|
+
*
|
|
98
|
+
* ---
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* clock.onStop(() => { [...] }); // This callback will be executed.
|
|
103
|
+
* clock.stop();
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
public override stop(): void
|
|
35
107
|
{
|
|
36
|
-
if (!(this._isRunning)) { throw new RuntimeException("The clock hadn't yet started."); }
|
|
108
|
+
if (!(this._isRunning)) { throw new RuntimeException("The clock had already stopped or hadn't yet started."); }
|
|
109
|
+
if (!(this._handle)) { throw new FatalErrorException(); }
|
|
37
110
|
|
|
38
|
-
|
|
111
|
+
this._stop();
|
|
112
|
+
this._handle = undefined;
|
|
113
|
+
this._isRunning = false;
|
|
39
114
|
|
|
40
115
|
this._publisher.publish("stop");
|
|
41
116
|
}
|
|
42
117
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Subscribes to the `tick` event of the clock.
|
|
120
|
+
*
|
|
121
|
+
* ---
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```ts
|
|
125
|
+
* clock.onTick((elapsedTime) => { [...] }); // This callback will be executed.
|
|
126
|
+
* clock.start();
|
|
127
|
+
* ```
|
|
128
|
+
*
|
|
129
|
+
* ---
|
|
130
|
+
*
|
|
131
|
+
* @param callback The callback that will be executed when the clock ticks.
|
|
132
|
+
* @param tickStep
|
|
133
|
+
* The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.
|
|
134
|
+
*
|
|
135
|
+
* - If it's a positive number, the callback will be executed only if the
|
|
136
|
+
* time passed from the previous execution is greater than this number.
|
|
137
|
+
* - If it's `0`, the callback will be executed every tick without even checking for the time.
|
|
138
|
+
* - If it's a negative number, a {@link RangeException} will be thrown.
|
|
139
|
+
*
|
|
140
|
+
* @returns A function that can be used to unsubscribe from the event.
|
|
141
|
+
*/
|
|
52
142
|
public onTick(callback: (elapsedTime: number) => void, tickStep = 0): () => void
|
|
53
143
|
{
|
|
54
144
|
if (tickStep < 0) { throw new RangeException("The tick step must be a non-negative number."); }
|
|
@@ -65,5 +155,5 @@ export default class Clock extends GameLoop
|
|
|
65
155
|
});
|
|
66
156
|
}
|
|
67
157
|
|
|
68
|
-
public readonly [Symbol.toStringTag]: string = "Clock";
|
|
158
|
+
public override readonly [Symbol.toStringTag]: string = "Clock";
|
|
69
159
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { TimeUnit } from "../../utils/date.js";
|
|
2
2
|
|
|
3
|
+
import Publisher from "../callbacks/publisher.js";
|
|
3
4
|
import { FatalErrorException, RangeException, RuntimeException } from "../exceptions/index.js";
|
|
4
5
|
import { DeferredPromise, SmartPromise } from "../promises/index.js";
|
|
6
|
+
import type { Callback } from "../types.js";
|
|
5
7
|
|
|
6
|
-
import
|
|
7
|
-
import GameLoop from "../game-loop.js";
|
|
8
|
+
import GameLoop from "./game-loop.js";
|
|
8
9
|
|
|
9
10
|
interface CountdownEventMap
|
|
10
11
|
{
|
|
@@ -12,37 +13,100 @@ interface CountdownEventMap
|
|
|
12
13
|
stop: (reason: unknown) => void;
|
|
13
14
|
tick: (remainingTime: number) => void;
|
|
14
15
|
expire: () => void;
|
|
16
|
+
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
[key: string]: Callback<any[], any>;
|
|
15
19
|
}
|
|
16
20
|
|
|
21
|
+
/**
|
|
22
|
+
* A class representing a countdown.
|
|
23
|
+
*
|
|
24
|
+
* It can be started, stopped, when running it ticks at a specific frame rate and it expires when the time's up.
|
|
25
|
+
* It's possible to subscribe to these events to receive notifications when they occur.
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const countdown = new Countdown(10_000);
|
|
29
|
+
*
|
|
30
|
+
* countdown.onStart(() => { console.log("The countdown has started."); });
|
|
31
|
+
* countdown.onTick((remainingTime) => { console.log(`The countdown has ${remainingTime}ms remaining.`); });
|
|
32
|
+
* countdown.onStop((reason) => { console.log(`The countdown has stopped because of ${reason}.`); });
|
|
33
|
+
* countdown.onExpire(() => { console.log("The countdown has expired."); });
|
|
34
|
+
*
|
|
35
|
+
* countdown.start();
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
17
38
|
export default class Countdown extends GameLoop
|
|
18
39
|
{
|
|
19
|
-
|
|
20
|
-
|
|
40
|
+
/**
|
|
41
|
+
* The {@link Publisher} object that will be used to publish the events of the countdown.
|
|
42
|
+
*/
|
|
43
|
+
protected override _publisher: Publisher<CountdownEventMap>;
|
|
21
44
|
|
|
45
|
+
/**
|
|
46
|
+
* The total duration of the countdown in milliseconds.
|
|
47
|
+
*
|
|
48
|
+
* This protected property is the only one that can be modified directly by the derived classes.
|
|
49
|
+
* If you're looking for the public and readonly property, use the {@link Countdown.duration} getter instead.
|
|
50
|
+
*/
|
|
22
51
|
protected _duration: number;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The total duration of the countdown in milliseconds.
|
|
55
|
+
*/
|
|
23
56
|
public get duration(): number
|
|
24
57
|
{
|
|
25
58
|
return this._duration;
|
|
26
59
|
}
|
|
27
60
|
|
|
61
|
+
/**
|
|
62
|
+
* The remaining time of the countdown in milliseconds.
|
|
63
|
+
* It's calculated as the difference between the total duration and the elapsed time.
|
|
64
|
+
*/
|
|
28
65
|
public get remainingTime(): number
|
|
29
66
|
{
|
|
30
67
|
return this._duration - this.elapsedTime;
|
|
31
68
|
}
|
|
32
69
|
|
|
70
|
+
/**
|
|
71
|
+
* The {@link DeferredPromise} that will be resolved or rejected when the countdown expires or stops.
|
|
72
|
+
*/
|
|
73
|
+
protected _deferrer?: DeferredPromise<void>;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Initializes a new instance of the {@link Countdown} class.
|
|
77
|
+
*
|
|
78
|
+
* ---
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* const countdown = new Countdown(10_000);
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* ---
|
|
86
|
+
*
|
|
87
|
+
* @param duration
|
|
88
|
+
* The total duration of the countdown in milliseconds.
|
|
89
|
+
*
|
|
90
|
+
* @param msIfNotBrowser
|
|
91
|
+
* The interval in milliseconds at which the countdown will tick if the environment is not a browser.
|
|
92
|
+
* `TimeUnit.Second` by default.
|
|
93
|
+
*/
|
|
33
94
|
public constructor(duration: number, msIfNotBrowser: number = TimeUnit.Second)
|
|
34
95
|
{
|
|
35
96
|
const callback = () =>
|
|
36
97
|
{
|
|
37
98
|
const remainingTime = this.remainingTime;
|
|
38
|
-
this._publisher.publish("tick", remainingTime);
|
|
39
|
-
|
|
40
99
|
if (remainingTime <= 0)
|
|
41
100
|
{
|
|
42
101
|
this._deferrerStop();
|
|
43
102
|
|
|
103
|
+
this._publisher.publish("tick", 0);
|
|
44
104
|
this._publisher.publish("expire");
|
|
45
105
|
}
|
|
106
|
+
else
|
|
107
|
+
{
|
|
108
|
+
this._publisher.publish("tick", remainingTime);
|
|
109
|
+
}
|
|
46
110
|
};
|
|
47
111
|
|
|
48
112
|
super(callback, msIfNotBrowser);
|
|
@@ -51,12 +115,24 @@ export default class Countdown extends GameLoop
|
|
|
51
115
|
this._duration = duration;
|
|
52
116
|
}
|
|
53
117
|
|
|
118
|
+
/**
|
|
119
|
+
* The internal method actually responsible for stopping the
|
|
120
|
+
* countdown and resolving or rejecting the {@link Countdown._deferrer} promise.
|
|
121
|
+
*
|
|
122
|
+
* @param reason
|
|
123
|
+
* The reason why the countdown has stopped.
|
|
124
|
+
*
|
|
125
|
+
* - If it's `undefined`, the promise will be resolved.
|
|
126
|
+
* - If it's a value, the promise will be rejected with that value.
|
|
127
|
+
*/
|
|
54
128
|
protected _deferrerStop(reason?: unknown): void
|
|
55
129
|
{
|
|
56
130
|
if (!(this._isRunning)) { throw new RuntimeException("The countdown hadn't yet started."); }
|
|
57
131
|
if (!(this._deferrer)) { throw new FatalErrorException(); }
|
|
58
132
|
|
|
59
|
-
|
|
133
|
+
this._stop();
|
|
134
|
+
this._handle = undefined;
|
|
135
|
+
this._isRunning = false;
|
|
60
136
|
|
|
61
137
|
if (reason !== undefined) { this._deferrer.reject(reason); }
|
|
62
138
|
else { this._deferrer.resolve(); }
|
|
@@ -64,9 +140,30 @@ export default class Countdown extends GameLoop
|
|
|
64
140
|
this._deferrer = undefined;
|
|
65
141
|
}
|
|
66
142
|
|
|
67
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Starts the execution of the countdown.
|
|
145
|
+
*
|
|
146
|
+
* If the countdown is already running, a {@link RuntimeException} will be thrown.
|
|
147
|
+
*
|
|
148
|
+
* ---
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* countdown.onStart(() => { [...] }); // This callback will be executed.
|
|
153
|
+
* countdown.start();
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* ---
|
|
157
|
+
*
|
|
158
|
+
* @param remainingTime
|
|
159
|
+
* The remaining time to set as default when the countdown starts.
|
|
160
|
+
* Default is the {@link Countdown.duration} itself.
|
|
161
|
+
*
|
|
162
|
+
* @returns A {@link SmartPromise} that will be resolved or rejected when the countdown expires or stops.
|
|
163
|
+
*/
|
|
164
|
+
public override start(remainingTime: number = this.duration): SmartPromise<void>
|
|
68
165
|
{
|
|
69
|
-
if (this._isRunning) { throw new RuntimeException("The countdown
|
|
166
|
+
if (this._isRunning) { throw new RuntimeException("The countdown had already stopped or hadn't yet started."); }
|
|
70
167
|
if (this._deferrer) { throw new FatalErrorException(); }
|
|
71
168
|
|
|
72
169
|
this._deferrer = new DeferredPromise();
|
|
@@ -76,33 +173,91 @@ export default class Countdown extends GameLoop
|
|
|
76
173
|
|
|
77
174
|
return this._deferrer;
|
|
78
175
|
}
|
|
79
|
-
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Stops the execution of the countdown.
|
|
179
|
+
*
|
|
180
|
+
* If the countdown hasn't yet started, a {@link RuntimeException} will be thrown.
|
|
181
|
+
*
|
|
182
|
+
* ---
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* countdown.onStop(() => { [...] }); // This callback will be executed.
|
|
187
|
+
* countdown.stop();
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* ---
|
|
191
|
+
*
|
|
192
|
+
* @param reason
|
|
193
|
+
* The reason why the countdown has stopped.
|
|
194
|
+
*
|
|
195
|
+
* - If it's `undefined`, the promise will be resolved.
|
|
196
|
+
* - If it's a value, the promise will be rejected with that value.
|
|
197
|
+
*/
|
|
198
|
+
public override stop(reason?: unknown): void
|
|
80
199
|
{
|
|
200
|
+
// TODO: Once solved Issues #6 & #10, make the `reason` parameter required.
|
|
201
|
+
// - https://github.com/Byloth/core/issues/6
|
|
202
|
+
// - https://github.com/Byloth/core/issues/10
|
|
203
|
+
//
|
|
81
204
|
this._deferrerStop(reason);
|
|
82
205
|
|
|
83
206
|
this._publisher.publish("stop", reason);
|
|
84
207
|
}
|
|
85
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Subscribes to the `expire` event of the countdown.
|
|
211
|
+
*
|
|
212
|
+
* ---
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* countdown.onExpire(() => { [...] }); // This callback will be executed once the countdown has expired.
|
|
217
|
+
* countdown.start();
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* ---
|
|
221
|
+
*
|
|
222
|
+
* @param callback The callback that will be executed when the countdown expires.
|
|
223
|
+
*
|
|
224
|
+
* @returns A function that can be used to unsubscribe from the event.
|
|
225
|
+
*/
|
|
86
226
|
public onExpire(callback: () => void): () => void
|
|
87
227
|
{
|
|
88
228
|
return this._publisher.subscribe("expire", callback);
|
|
89
229
|
}
|
|
90
230
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
231
|
+
/**
|
|
232
|
+
* Subscribes to the `tick` event of the countdown.
|
|
233
|
+
*
|
|
234
|
+
* ---
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* countdown.onTick((remainingTime) => { [...] }); // This callback will be executed.
|
|
239
|
+
* countdown.start();
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* ---
|
|
243
|
+
*
|
|
244
|
+
* @param callback The callback that will be executed when the countdown ticks.
|
|
245
|
+
* @param tickStep
|
|
246
|
+
* The minimum time in milliseconds that must pass from the previous execution of the callback to the next one.
|
|
247
|
+
*
|
|
248
|
+
* - If it's a positive number, the callback will be executed only if the
|
|
249
|
+
* time passed from the previous execution is greater than this number.
|
|
250
|
+
* - If it's `0`, the callback will be executed every tick without even checking for the time.
|
|
251
|
+
* - If it's a negative number, a {@link RangeException} will be thrown.
|
|
252
|
+
*
|
|
253
|
+
* @returns A function that can be used to unsubscribe from the event.
|
|
254
|
+
*/
|
|
100
255
|
public onTick(callback: (remainingTime: number) => void, tickStep = 0): () => void
|
|
101
256
|
{
|
|
102
257
|
if (tickStep < 0) { throw new RangeException("The tick step must be a non-negative number."); }
|
|
103
258
|
if (tickStep === 0) { return this._publisher.subscribe("tick", callback); }
|
|
104
259
|
|
|
105
|
-
let lastTick =
|
|
260
|
+
let lastTick = this.remainingTime;
|
|
106
261
|
|
|
107
262
|
return this._publisher.subscribe("tick", (remainingTime: number) =>
|
|
108
263
|
{
|
|
@@ -113,5 +268,5 @@ export default class Countdown extends GameLoop
|
|
|
113
268
|
});
|
|
114
269
|
}
|
|
115
270
|
|
|
116
|
-
public readonly [Symbol.toStringTag]: string = "Countdown";
|
|
271
|
+
public override readonly [Symbol.toStringTag]: string = "Countdown";
|
|
117
272
|
}
|