Как определить конструктор для класса, расширяющего Date?

Как правильно определить конструктор для дочернего класса Date (машинописный текст 4.1.3)?

Определение конструктора объекта Date следующее:

new(): Date;
new(value: number | string): Date;
new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;

в моем коде я пытаюсь указать это:

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)
         */         
    }
}

но это вызывает ошибку компиляции в супервызове:

Argument of type 'string | number | undefined' is not assignable to parameter of type 'number'.
Type 'undefined' is not assignable to type 'number'.(2345)

Как я могу определить параметры конструктора, чтобы я мог вызвать super со всеми возможностями, которые есть у исходного объекта Date, и сохранить безопасность типов (насколько это возможно)?

Примечания:


person TmTron    schedule 19.01.2021    source источник
comment
К черту: @ts-ignore constructor(...args) { super(...args) }.   -  person Bergi    schedule 19.01.2021
comment
@Bergi - Ага. Это тоже вполне разумный вариант.   -  person T.J. Crowder    schedule 19.01.2021


Ответы (2)


Если вы хотите поддерживать все подписи, которые поддерживает Date, ¹ Я не думаю, что у вас есть другой выбор, кроме ветвления (или 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);
        }
    }
}

площадка ссылка


¹ (Как бы то ни было, я не думаю, что у вас есть , хотя вы вполне можете захотеть. В отличие от Array или Promise, я не думаю, что конструктор Date вызывается где-нибудь в стандартная библиотека)

person T.J. Crowder    schedule 19.01.2021

Вам нужно добавить некоторую проверку и вызвать соответствующий родительский конструктор для каждой ситуации:

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)
        }
    }

рабочая ссылка детской площадки

person gbalduzzi    schedule 19.01.2021
comment
Если вы предлагаете имитировать, как конструктор Date обрабатывает аргументы, вам следует следовать шаблону в ECMA-262.. Это означало бы сначала подсчитать количество аргументов, иначе new MyDate(2021, undefined) в подклассе будет вести себя иначе, чем конструктор Date при тех же значениях. Кроме того, значения, передаваемые конструктору Date, могут быть строками или числами. Первый аргумент также может быть объектом (например, экземпляром Date). - person RobG; 20.01.2021