Reputation: 19411
How can I correctly define the constructor for a child-class of Date (typescript 4.1.3)?
The constructor definition of the Date object is this:
new(): Date;
new(value: number | string): Date;
new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
in my code, I try to specify this:
class MyDate extends Date {
// overloads copied from DateConstructor
constructor();
constructor(value: number | string);
constructor(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number);
// constructor impl
constructor(
yearOrValue?: number | string, month?: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number
) {
super(yearOrValue, month, date, hours, minutes, seconds, ms);
/* ^^^^^^^^^^^
Argument of type 'string | number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.(2345)
*/
}
}
but this causes a compile error in the super call:
Argument of type 'string | number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.(2345)
How can I define the constructor parameters, so that I can call super with all possibilities that the original Date object has and keep type-safety (as much as possible)?
Notes:
Upvotes: 2
Views: 863
Reputation: 447
I had the same issue and implementing it like this fixed all the TS errors:
class MyDate extends Date {
constructor();
constructor(value: number | string);
constructor(
year: number,
month: number,
date?: number,
hours?: number,
minutes?: number,
seconds?: number,
ms?: number,
);
constructor(
...args: [] | [number | string] | [number, number, number?, number?, number?, number?, number?]
) {
if (args.length === 0) {
super();
} else if (args.length === 1) {
super(args[0]);
} else {
super(...args);
}
}
}
Upvotes: 0
Reputation: 14502
You could do something like this today:
class MyDate extends Date {
constructor(...args: ConstructorParameters<typeof Date>) {
super(...args)
}
}
Upvotes: 2
Reputation: 1075139
If you want to support all of the signatures that Date
supports,¹ I don't think you have much choice other than branching (or punting):
class MyDate extends Date {
// overloads copied from DateConstructor
constructor();
constructor(value: number | string);
constructor(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number);
// constructor impl
constructor(
yearOrValue?: number | string,
month?: number,
date?: number,
hours?: number,
minutes?: number,
seconds?: number,
ms?: number
) {
if (typeof yearOrValue === "undefined") {
super();
} else if (typeof month === "undefined") {
super(yearOrValue);
} else {
// consider an assertion here that `yearOrValue` is a number
super(yearOrValue as number, month, date, hours, minutes, seconds, ms);
}
}
}
¹ (For what it's worth, I don't think you have to, though you may well want to. Unlike Array
or Promise
, I don't think the Date
constructor is called anywhere in the standard library)
Upvotes: 4
Reputation: 10166
You need to add some check and call the proper parent constructor for each situation:
constructor(
yearOrValue?: number | string, month?: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number
) {
if (yearOrValue === undefined) {
super()
} else if (month === undefined) {
super(yearOrValue)
} else if (typeof yearOrValue === 'number') {
super(yearOrValue, month, date, hours, minutes, seconds, ms)
}
}
Upvotes: 2