【问题标题】:How to define the constructor for a class that extends Date?如何为扩展 Date 的类定义构造函数?
【发布时间】:2021-01-19 16:51:30
【问题描述】:

如何正确定义 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)

如何定义构造函数参数,以便我可以在原始 Date 对象具有的所有可能性下调用 super 并保持类型安全(尽可能)?

注意事项:

  • 这里是typescript playground example 的链接
  • 这只是一些测试代码,在生产版本中我在构造函数中有更多代码
  • 我想要一个适用于类的解决方案(即不会弄乱原型等)

【问题讨论】:

  • 搞砸了:@ts-ignore constructor(...args) { super(...args) }.
  • @Bergi - 是的。这也是一个非常合理的选择。

标签: javascript typescript datetime constructor-overloading


【解决方案1】:

如果您想支持 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);
        }
    }
}

Playground link


¹ (对于它的价值,我不认为你,尽管你可能很想这样做。不像ArrayPromise,我不认为Date 构造函数在标准库中的任何位置调用)

【讨论】:

    【解决方案2】:

    您需要为每种情况添加一些检查并调用正确的父构造函数:

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

    Working playground link

    【讨论】:

    • 如果您建议模仿 Date 构造函数如何处理参数,那么您应该遵循pattern in ECMA-262。这意味着首先计算参数的数量,否则“子类”中的new MyDate(2021, undefined) 将与给定相同值的 Date 构造函数的行为不同。此外,传递给 Date 构造函数的值都可以是字符串或数字。第一个参数也可以是一个对象(例如 Date 实例)。
    猜你喜欢
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 2013-01-30
    • 2018-09-26
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 2013-11-15
    相关资源
    最近更新 更多