【问题标题】:TypeScript interface signature "(): string"TypeScript 接口签名“():字符串”
【发布时间】:2018-04-01 18:15:22
【问题描述】:

在标准 Node.js 库的类型定义中,我找到了接口 DateConstructor 的定义。

interface DateConstructor {
    new(): Date;
    new(value: number): Date;
    new(value: string): Date;
    new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
    (): string;
    readonly prototype: Date;
    /**
      * Parses a string containing a date, and returns the number of milliseconds between that date and midnight, January 1, 1970.
      * @param s A date string
      */
    parse(s: string): number;
    /**
      * Returns the number of milliseconds between midnight, January 1, 1970 Universal Coordinated Time (UTC) (or GMT) and the specified date.
      * @param year The full year designation is required for cross-century date accuracy. If year is between 0 and 99 is used, then year is assumed to be 1900 + year.
      * @param month The month as an number between 0 and 11 (January to December).
      * @param date The date as an number between 1 and 31.
      * @param hours Must be supplied if minutes is supplied. An number from 0 to 23 (midnight to 11pm) that specifies the hour.
      * @param minutes Must be supplied if seconds is supplied. An number from 0 to 59 that specifies the minutes.
      * @param seconds Must be supplied if milliseconds is supplied. An number from 0 to 59 that specifies the seconds.
      * @param ms An number from 0 to 999 that specifies the milliseconds.
      */
    UTC(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number;
    now(): number;
}

declare const Date: DateConstructor;

它包含奇怪的定义(): string。我如何在类中定义它,想要实现这个接口?

【问题讨论】:

标签: javascript node.js class typescript interface


【解决方案1】:

如果您认为这个问题与the other one I linked to 足够不同:

该定义意味着类构造函数也是一个没有参数的可调用函数,在没有new 的情况下调用时返回一个字符串。您不能使用ES2015-或-later class 并遵守规范,因为在没有new 的情况下调用它时需要抛出TypeError。相反,您可以返回一个检测被 new 调用的函数,并添加额外的属性来实现静态方法。

我会给你一个例子,我提供了一个围绕内置 Date 构造函数对象的包装器。首先让我们来描述一下接口中充当函数的部分,不管有没有new关键字:

interface FunctionalPartOfDateConstructor {
  new(): Date;
  new(value: number): Date;
  new(value: string): Date;
  new(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
  (): string;
}

现在让我们尝试实现这部分:

const funcPart = function(valueOrYear?: number | string, month?: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date | string {
  if (typeof new.target === 'undefined') {
    // called as function
    return Date();
  }
  if (typeof valueOrYear === 'undefined') {
    // called as constructor with no arguments
    return new Date();
  }
  if (typeof valueOrYear === 'string') {
    // called as constructor with string value argument
    return new Date(valueOrYear);
  }
  if (typeof month === 'undefined') {
    // called as constructor with number value argument
    return new Date(valueOrYear);
  }
  // called as constructor with year, month, date, etc arguments:
  return new Date(valueOrYear, month, date, hours, minutes, seconds, ms);
} as FunctionalPartOfDateConstructor;

请注意,我使用new.target 来检测函数是否使用new 调用。我认为,当以 ES5 为目标时,这编译为合理的东西。请注意,它必须梳理所有不同重载签名之间的差异。

现在我们可以通过将功能部分与实现静态方法的东西合并来制作完整的 DateConstructor 实例:

const myDateConstructor: DateConstructor = Object.assign(funcPart, {
  prototype: Date.prototype,
  parse(s: string) {
    return Date.parse(s);
  },
  UTC(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number) {
    return Date.UTC(year, month, date, hours, minutes, seconds, ms);
  },
  now() {
    return Date.now();
  }
})

如果你愿意,你可以try it on the TypeScript Playground。希望有帮助;祝你好运!

【讨论】:

  • 谢谢。这对我很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 2018-12-13
  • 1970-01-01
  • 1970-01-01
  • 2019-06-23
  • 2020-11-04
相关资源
最近更新 更多