Skip to content

Commit 6536084

Browse files
authored
fix: fix object constructor typings & make OC generic type optional (#712)
1 parent c2f9950 commit 6536084

File tree

5 files changed

+49
-26
lines changed

5 files changed

+49
-26
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Parameter Based
118118
- `constructor(cronTime, onTick, onComplete, start, timeZone, context, runOnInit, utcOffset, unrefTimeout)`
119119
- `cronTime` - [REQUIRED] - The time to fire off your job. This can be in the form of cron syntax or a JS [Date](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date) object.
120120
- `onTick` - [REQUIRED] - The function to fire at the specified time. If an `onComplete` callback was provided, `onTick` will receive it as an argument. `onTick` may call `onComplete` when it has finished its work.
121-
- `onComplete` - [OPTIONAL] - A function that will fire when the job is stopped with `job.stop()`, and may also be called by `onTick` at the end of each run.
121+
- `onComplete` - [OPTIONAL] - A function that will fire when the job is stopped with `job.stop()`, and may also be called by `onTick` at the end of each run. **Note for TS users**: This should either be an arrow function, or a regular function cast to `() => void` (bug with generic type inference).
122122
- `start` - [OPTIONAL] - Specifies whether to start the job just before exiting the constructor. By default this is set to false. If left at default you will need to call `job.start()` in order to start the job (assuming `job` is the variable you set the cronjob to). This does not immediately fire your `onTick` function, it just gives you more control over the behavior of your jobs.
123123
- `timeZone` - [OPTIONAL] - Specify the time zone for the execution. This will modify the actual time relative to your time zone. If the time zone is invalid, an error is thrown. By default (if this is omitted) the local time zone will be used. You can check the various time zones format accepted in the [Luxon documentation](https://github.com/moment/luxon/blob/master/docs/zones.md#specifying-a-zone). Note: This parameter supports minutes offsets, e.g. `UTC+5:30`. **Note**: Cannot be used together with `utcOffset`.
124124
- `context` - [OPTIONAL] - The context within which to execute the onTick method. This defaults to the cronjob itself allowing you to call `this.stop()`. However, if you change this you'll have access to the functions and values within your context object.

src/job.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import {
1111
WithOnComplete
1212
} from './types/cron.types';
1313

14-
export class CronJob<OC extends CronOnCompleteCommand<C> | null, C = null> {
14+
export class CronJob<OC extends CronOnCompleteCommand | null = null, C = null> {
1515
cronTime: CronTime;
1616
running = false;
1717
unrefTimeout = false;
1818
lastExecution: Date | null = null;
1919
runOnce = false;
2020
context: CronContext<C>;
2121
onComplete?: WithOnComplete<OC> extends true
22-
? CronOnCompleteCallback<C>
22+
? CronOnCompleteCallback
2323
: undefined;
2424

2525
private _timeout?: NodeJS.Timeout;
@@ -81,9 +81,7 @@ export class CronJob<OC extends CronOnCompleteCommand<C> | null, C = null> {
8181
// casting to the correct type since we just made sure that WithOnComplete<OC> = true
8282
this.onComplete = this._fnWrap(
8383
onComplete
84-
) as WithOnComplete<OC> extends true
85-
? CronOnCompleteCallback<C>
86-
: undefined;
84+
) as WithOnComplete<OC> extends true ? CronOnCompleteCallback : undefined;
8785
}
8886

8987
if (this.cronTime.realDate) {
@@ -100,7 +98,7 @@ export class CronJob<OC extends CronOnCompleteCommand<C> | null, C = null> {
10098
if (start) this.start();
10199
}
102100

103-
static from<C = null, OC extends CronOnCompleteCommand<C> | null = null>(
101+
static from<OC extends CronOnCompleteCommand | null = null, C = null>(
104102
params: CronJobParams<OC, C>
105103
) {
106104
// runtime check for JS users
@@ -196,7 +194,7 @@ export class CronJob<OC extends CronOnCompleteCommand<C> | null, C = null> {
196194
callback.call(
197195
this.context,
198196
this.onComplete as WithOnComplete<OC> extends true
199-
? CronOnCompleteCallback<C>
197+
? CronOnCompleteCallback
200198
: never
201199
);
202200
}

src/time.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -37,19 +37,19 @@ export class CronTime {
3737
private dayOfWeek: TimeUnitField<'dayOfWeek'> = {};
3838

3939
constructor(
40-
source: CronJobParams<null>['cronTime'],
41-
timeZone?: CronJobParams<null>['timeZone'],
40+
source: CronJobParams['cronTime'],
41+
timeZone?: CronJobParams['timeZone'],
4242
utcOffset?: null
4343
);
4444
constructor(
45-
source: CronJobParams<null>['cronTime'],
45+
source: CronJobParams['cronTime'],
4646
timeZone?: null,
47-
utcOffset?: CronJobParams<null>['utcOffset']
47+
utcOffset?: CronJobParams['utcOffset']
4848
);
4949
constructor(
50-
source: CronJobParams<null>['cronTime'],
51-
timeZone?: CronJobParams<null>['timeZone'],
52-
utcOffset?: CronJobParams<null>['utcOffset']
50+
source: CronJobParams['cronTime'],
51+
timeZone?: CronJobParams['timeZone'],
52+
utcOffset?: CronJobParams['utcOffset']
5353
) {
5454
// runtime check for JS users
5555
if (timeZone != null && utcOffset != null) {

src/types/cron.types.ts

+6-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { CronJob } from '../job';
55
import { IntRange } from './utils';
66

77
interface BaseCronJobParams<
8-
OC extends CronOnCompleteCommand<C> | null,
8+
OC extends CronOnCompleteCommand | null = null,
99
C = null
1010
> {
1111
cronTime: string | Date | DateTime;
@@ -18,7 +18,7 @@ interface BaseCronJobParams<
1818
}
1919

2020
export type CronJobParams<
21-
OC extends CronOnCompleteCommand<C> | null,
21+
OC extends CronOnCompleteCommand | null = null,
2222
C = null
2323
> =
2424
| BaseCronJobParams<OC, C> &
@@ -33,16 +33,14 @@ export type CronJobParams<
3333
}
3434
);
3535

36-
export type CronContext<C> = C extends null ? CronJob<null> : NonNullable<C>;
36+
export type CronContext<C> = C extends null ? CronJob : NonNullable<C>;
3737

3838
export type CronCallback<C, WithOnCompleteBool extends boolean = false> = (
3939
this: CronContext<C>,
40-
onComplete: WithOnCompleteBool extends true
41-
? OmitThisParameter<CronOnCompleteCallback<C>>
42-
: never
40+
onComplete: WithOnCompleteBool extends true ? CronOnCompleteCallback : never
4341
) => void;
4442

45-
export type CronOnCompleteCallback<C> = (this: CronContext<C>) => void;
43+
export type CronOnCompleteCallback = () => void;
4644

4745
export type CronSystemCommand =
4846
| string
@@ -56,9 +54,7 @@ export type CronCommand<C, WithOnCompleteBool extends boolean = false> =
5654
| CronCallback<C, WithOnCompleteBool>
5755
| CronSystemCommand;
5856

59-
export type CronOnCompleteCommand<C> =
60-
| OmitThisParameter<CronOnCompleteCallback<C>>
61-
| CronSystemCommand;
57+
export type CronOnCompleteCommand = CronOnCompleteCallback | CronSystemCommand;
6258

6359
export type WithOnComplete<OC> = OC extends null ? false : true;
6460

tests/cron.test.ts

+30-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ describe('cron', () => {
329329
expect(t.getSeconds()).toBe(d.getSeconds());
330330
onComplete();
331331
},
332-
function () {
332+
() => {
333333
callback();
334334
resolve();
335335
},
@@ -344,6 +344,35 @@ describe('cron', () => {
344344
expect(callback).toHaveBeenCalledTimes(2);
345345
});
346346

347+
it('should run on a specific date and call onComplete from onTick using the object constructor', async () => {
348+
const d = new Date();
349+
const clock = sinon.useFakeTimers(d.getTime());
350+
d.setSeconds(d.getSeconds() + 1);
351+
const callback = jest.fn();
352+
353+
await new Promise<void>(resolve => {
354+
const job = CronJob.from({
355+
cronTime: d,
356+
onTick: onComplete => {
357+
const t = new Date();
358+
expect(t.getSeconds()).toBe(d.getSeconds());
359+
onComplete();
360+
},
361+
onComplete: function () {
362+
callback();
363+
resolve();
364+
} as () => void,
365+
start: true
366+
});
367+
clock.tick(1000);
368+
clock.restore();
369+
job.stop();
370+
});
371+
372+
// onComplete is called 2 times: once in onTick() & once when calling job.stop()
373+
expect(callback).toHaveBeenCalledTimes(2);
374+
});
375+
347376
it("should not be able to call onComplete from onTick if if wasn't provided", () => {
348377
expect.assertions(4);
349378
const d = new Date();

0 commit comments

Comments
 (0)