Spec
According to the MDN specification for Array.prototype.map() map should be used like this...
var new_array = arr.map(callback[, thisArg])
Problem
TypeScript has several overloaded declarations for map, and this makes it very difficult to extend Array<T>
.
I would expect to see this (which is in lib.d.ts)...
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
But lib.d.ts also has these...
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];
Objection
Since JavaScript does not allow method overloading, and neither does TypeScript for class implementation, I don't think that TypeScript should allow this for ambient declarations either.
Questions
I've raised this on GitHub too... https://github.com/Microsoft/TypeScript/issues/13785
Note
ReadonlyArray<T>
only has a single signature for map, which is...
map<U>(callbackfn: (value: T, index: number, array: ReadonlyArray<T>) => U, thisArg?: any): U[];
Array.prototype.map() The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
The map() method returns an entirely new array with transformed elements and the same amount of data. In the case of forEach() , even if it returns undefined , it will mutate the original array with the callback .
Definition and Usage. map() creates a new array from calling a function for every array element. map() calls a function once for each element in an array. map() does not execute the function for empty elements. map() does not change the original array.
The map() method in JavaScript creates an array by calling a specific function on each element present in the parent array. It is a non-mutating method. Generally map() method is used to iterate over an array and calling function on every element of array.
(1) If it wouldn't be allowed to overload signatures in ambient declarations how would you get the different signatures in the native js functions/methods?
There are a lot of overloads in the lib.d.ts
which reflects how the native js objects work.
(2) You need to tell the compiler that you're covering all of the possible declared signatures.
In your case you can do something like:
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 [];
}
}
The first overload signature takes care of the ones you don't want to bother with.
Your question touches different aspects of TypeScript. I'll handle them individually and then put them all together.
Array<T>
Interfaces serve a dual purpose in TypeScript:
.d.ts
file (and lib.d.ts
file contains the basic JavaScript types). These interfaces are tailored to the existing type and they are usually not meant for you to implement. You can though if you want, but you have to implement all its members.The Array<T>
interface is of the second kind and as such it is not meant for you to implement.
this
Parameters in Functions
The this:
parameter in the function definition is not a real parameter in the sense that you can pass arguments. It allows you specify which type you expect the this
value in the function body to be. If you don't specify it, this
will be of type any
, which is often not very useful.
Function/Method Overloading
In TypeScript, functions and methods are not overloaded in the sense they are overloaded in languages like Java or C#. You cannot implement it more often than once, but you can define alternate signatures to allow static typing for functions that return variant types or use variant parameters. Especially in .d.ts
definition files this is useful and often necessary, since existing libraries use the weak typing of JavaScript to return values or expect parameters of different types. That makes your objection false. You need function overloading to accommodate these JavaScript constructs.
Tuples
In a JavaScript array you can assign values of multiple types in each of its slots. In a TypeScript array definition you specify one type, which the complier enforces. To fill the gap, you can define tuples. A type like [number, string, string]
translates to a JavaScript array any[]
and TypeScript can still enforce static typing.
Summary
The array method overloads you object against in Array<T>
introduce a statically typed this
parameter in the event the array is an actual [T, T]
, [T, T, T]
, [T, T, T, T]
, [T, T, T, T, T]
. It does not imply that the array provides multiple map
methods. It is the same method, but overloaded for some specific array types. It is provided in lib.d.ts
and as such was not designed to be implemented by you. You can extend the underlying class (which is already there even without the interface), but the overloads don't hurt you (at least not in this case, since they only provide this
parameters).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With