TypeScript Array.prototype.map 声明

TypeScript Array.prototype.map declaration

规格

根据MDN specification for Array.prototype.map()地图应该这样使用...

var new_array = arr.map(callback[, thisArg])

问题

TypeScript 有多个 map 的重载声明,这使得 extend Array<T>.

变得非常困难

我希望看到这个 (在 lib.d.ts 中)...

map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];

但是lib.d.ts也有这些...

map<U>(this: [T, T, T, T, T], callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): [U, U, U, U, U];

map<U>(this: [T, T, T, T], callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): [U, U, U, U];

map<U>(this: [T, T, T], callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): [U, U, U];

map<U>(this: [T, T], callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): [U, U];

异议

由于 JavaScript 不允许方法重载,class 实现的 TypeScript 也不允许,我认为 TypeScript 也不应该允许环境声明。

问题

  1. 为什么 TypeScript 允许环境声明的重载签名?
  2. 如何在扩展数组的 class 中覆盖地图实现?

我也在 GitHub 上提出过这个... https://github.com/Microsoft/TypeScript/issues/13785

备注

ReadonlyArray<T> 只有一个地图签名,即...

 map<U>(callbackfn: (value: T, index: number, array: ReadonlyArray<T>) => U, thisArg?: any): U[];

(1) 如果不允许在环境声明中重载签名,您将如何在本机 js 中获得不同的签名functions/methods?
lib.d.ts 中有很多重载反映了原生 js 对象的工作方式。

(2) 你需要告诉编译器你覆盖了所有可能声明的签名。
在您的情况下,您可以执行以下操作:

class A<T> extends Array<T> {
    map<U>(this: Array<U>, ...args: any[]);
    map<U>(this: Array<T>, callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[] {
        return [];
    }
}

第一个重载签名会处理那些您不想打扰的签名。

您的问题涉及 TypeScript 的不同方面。我会单独处理它们,然后将它们放在一起。

数组

接口在 TypeScript 中有双重用途:

  1. 它们允许您创建 "true" 接口供其他(尚不存在的)class 实现。当你实现它时,你必须完整地实现它,因为接口提供了所有成员可用的保证。
  2. 它们允许您定义已经存在 javascript 类型的接口。当你想使用众多现有库中的一个并且仍然具有静态类型的优势时,这非常有用。这些接口通常在 .d.ts 文件中定义(并且 lib.d.ts 文件包含基本的 Java 脚本类型)。这些接口是为现有类型量身定制的,它们通常不适合您实现。如果你愿意,你可以,但是你必须实现它的所有成员。

Array<T> 接口是第二种接口,因此不适合您实现。

this 函数中的参数

函数定义中的 this: 参数不是可以传递参数的真正参数。它允许您指定您希望函数体中的 this 值是哪种类型。如果您不指定它,this 将是 any 类型,这通常不是很有用。

Function/Method 重载

在 TypeScript 中,函数和方法不会在 Java 或 C# 等语言中重载。您不能多次实现它,但您可以定义替代签名以允许对 return 变体类型或使用变体参数的函数进行静态类型化。特别是在 .d.ts 定义文件中,这很有用,而且通常是必需的,因为现有库使用 JavaScript 的弱类型来 return 值或期望不同类型的参数。这使你的反对是错误的。您需要函数重载来适应这些 Java脚本结构。

元组

在Java脚本数组中,您可以在其每个槽中分配多种类型的值。在 TypeScript 数组定义中,您指定编译器强制执行的 one 类型。为了填补空白,您可以定义 tuples。像 [number, string, string] 这样的类型转换为 JavaScript 数组 any[] 并且 TypeScript 仍然可以强制执行静态类型。

总结

您在 Array<T> 中反对的数组方法重载引入了一个静态类型的 this 参数,如果数组是实际的 [T, T][T, T, T][T, T, T, T][T, T, T, T, T]。这并不意味着该数组提供了多个 map 方法。它是相同的方法,但对某些特定的数组类型进行了重载。它在 lib.d.ts 中提供,因此并非设计为由您实施。您可以扩展底层 class(即使没有接口也已经存在),但重载不会伤害您(至少在这种情况下不会,因为它们只提供 this 参数)。