Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better typings for Array.map() #33832

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1138,7 +1138,7 @@ interface ReadonlyArray<T> {
* @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
*/
map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): U[];
map<U>(callbackfn: (value: T, index: number, array: readonly T[]) => U, thisArg?: any): { -readonly [P in keyof this]: U } extends U[] ? { -readonly [P in keyof this]: U } : U[];
/**
* Returns the elements of an array that meet the condition specified in a callback function.
* @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
Expand Down Expand Up @@ -1308,7 +1308,7 @@ interface Array<T> {
* @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
*/
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): { -readonly [P in keyof this]: U } extends U[] ? { -readonly [P in keyof this]: U } : U[];
/**
* Returns the elements of an array that meet the condition specified in a callback function.
* @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(15,12): error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(16,5): error TS2461: Type 'StrNum' is not an array type.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(17,5): error TS2461: Type '{ 0: string; 1: number; length: 2; }' is not an array type.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(18,5): error TS2741: Property '2' is missing in type '[string, number]' but required in type '[number, number, number]'.
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(19,5): error TS2741: Property '2' is missing in type 'StrNum' but required in type '[number, number, number]'.
Expand Down Expand Up @@ -28,7 +29,7 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(31,5): error
tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(32,5): error TS2322: Type '{ 0: string; 1: number; length: 2; }' is not assignable to type '[number, string]'.


==== tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts (17 errors) ====
==== tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts (18 errors) ====
interface StrNum extends Array<string|number> {
0: string;
1: number;
Expand All @@ -47,6 +48,8 @@ tests/cases/conformance/types/tuple/arityAndOrderCompatibility01.ts(32,5): error
~
!!! error TS2493: Tuple type '[string, number]' of length '2' has no element at index '2'.
var [d, e, f] = y;
~~~~~~~~~
!!! error TS2461: Type 'StrNum' is not an array type.
var [g, h, i] = z;
~~~~~~~~~
!!! error TS2461: Type '{ 0: string; 1: number; length: 2; }' is not an array type.
Expand Down
6 changes: 3 additions & 3 deletions tests/baselines/reference/arityAndOrderCompatibility01.types
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ var [a, b, c] = x;
>x : [string, number]

var [d, e, f] = y;
>d : string
>e : number
>f : string | number
>d : any
>e : any
>f : any
>y : StrNum

var [g, h, i] = z;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,29 @@
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(13,1): error TS2322: Type 'A[]' is not assignable to type 'readonly B[]'.
Property 'b' is missing in type 'A' but required in type 'B'.
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(15,1): error TS2322: Type 'C<A>' is not assignable to type 'readonly A[]'.
The types returned by 'map(...)' are incompatible between these types.
Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]' is not assignable to type 'U[]'.
Type 'U[] | { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
Types of property 'length' are incompatible.
Type 'U' is not assignable to type 'number'.
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(16,1): error TS2322: Type 'C<B>' is not assignable to type 'readonly A[]'.
The types returned by 'map(...)' are incompatible between these types.
Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]' is not assignable to type 'U[]'.
Type 'U[] | { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
Types of property 'length' are incompatible.
Type 'U' is not assignable to type 'number'.
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(17,1): error TS2322: Type 'C<B>' is not assignable to type 'readonly B[]'.
The types returned by 'map(...)' are incompatible between these types.
Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]' is not assignable to type 'U[]'.
tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error TS2322: Type 'C<A>' is not assignable to type 'readonly B[]'.
The types returned by 'concat(...)' are incompatible between these types.
Type 'A[]' is not assignable to type 'B[]'.
Type 'A' is not assignable to type 'B'.


==== tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts (2 errors) ====
==== tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts (5 errors) ====
class A { a }
class B extends A { b }
class C<T> extends Array<T> { c }
Expand All @@ -26,8 +43,28 @@ tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error T
!!! related TS2728 tests/cases/compiler/arrayOfSubtypeIsAssignableToReadonlyArray.ts:2:21: 'b' is declared here.

rra = cra;
~~~
!!! error TS2322: Type 'C<A>' is not assignable to type 'readonly A[]'.
!!! error TS2322: The types returned by 'map(...)' are incompatible between these types.
!!! error TS2322: Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]' is not assignable to type 'U[]'.
!!! error TS2322: Type 'U[] | { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
!!! error TS2322: Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
!!! error TS2322: Types of property 'length' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'number'.
rra = crb; // OK, C<B> is assignable to ReadonlyArray<A>
~~~
!!! error TS2322: Type 'C<B>' is not assignable to type 'readonly A[]'.
!!! error TS2322: The types returned by 'map(...)' are incompatible between these types.
!!! error TS2322: Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]' is not assignable to type 'U[]'.
!!! error TS2322: Type 'U[] | { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
!!! error TS2322: Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; }' is not assignable to type 'U[]'.
!!! error TS2322: Types of property 'length' are incompatible.
!!! error TS2322: Type 'U' is not assignable to type 'number'.
rrb = crb;
~~~
!!! error TS2322: Type 'C<B>' is not assignable to type 'readonly B[]'.
!!! error TS2322: The types returned by 'map(...)' are incompatible between these types.
!!! error TS2322: Type '{ [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; c: U; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]' is not assignable to type 'U[]'.
rrb = cra; // error: 'A' is not assignable to 'B'
~~~
!!! error TS2322: Type 'C<A>' is not assignable to type 'readonly B[]'.
Expand Down
36 changes: 36 additions & 0 deletions tests/baselines/reference/bestChoiceType.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
tests/cases/compiler/bestChoiceType.ts(3,23): error TS2349: This expression is not callable.
Each member of the union type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.
tests/cases/compiler/bestChoiceType.ts(10,15): error TS2349: This expression is not callable.
Each member of the union type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.
tests/cases/compiler/bestChoiceType.ts(16,15): error TS2349: This expression is not callable.
Each member of the union type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.


==== tests/cases/compiler/bestChoiceType.ts (3 errors) ====
// Repro from #10041

(''.match(/ /) || []).map(s => s.toLowerCase());
~~~
!!! error TS2349: This expression is not callable.
!!! error TS2349: Each member of the union type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.

// Similar cases

function f1() {
let x = ''.match(/ /);
let y = x || [];
let z = y.map(s => s.toLowerCase());
~~~
!!! error TS2349: This expression is not callable.
!!! error TS2349: Each member of the union type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.
}

function f2() {
let x = ''.match(/ /);
let y = x ? x : [];
let z = y.map(s => s.toLowerCase());
~~~
!!! error TS2349: This expression is not callable.
!!! error TS2349: Each member of the union type '(<U>(callbackfn: (value: string, index: number, array: string[]) => U, thisArg?: any) => { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } extends U[] ? { [x: number]: U; index?: U | undefined; input?: U | undefined; length: U; toString: U; toLocaleString: U; pop: U; push: U; concat: U; join: U; reverse: U; shift: U; slice: U; sort: U; splice: U; unshift: U; indexOf: U; lastIndexOf: U; every: U; some: U; forEach: U; map: U; filter: U; reduce: U; reduceRight: U; } : U[]) | (<U>(callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.
}

Loading