Skip to content

Commit a4bf347

Browse files
committed
Array.prototype.sort - remove the need for compareFn to handle undefined values. Fixes #41708
1 parent 6df16b3 commit a4bf347

8 files changed

+21
-19
lines changed

src/lib/es5.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ interface Array<T> {
12671267
* [11,2,22,1].sort((a, b) => a - b)
12681268
* ```
12691269
*/
1270-
sort(compareFn?: (a: T, b: T) => number): this;
1270+
sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this;
12711271
/**
12721272
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
12731273
* @param start The zero-based location in the array from which to start removing elements.

tests/baselines/reference/implementArrayInterface.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ declare class MyArray<T> implements Array<T> {
1010
reverse(): T[];
1111
shift(): T;
1212
slice(start?: number, end?: number): T[];
13-
sort(compareFn?: (a: T, b: T) => number): this;
13+
sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this;
1414
splice(start: number): T[];
1515
splice(start: number, deleteCount: number, ...items: T[]): T[];
1616
unshift(...items: T[]): number;

tests/baselines/reference/implementArrayInterface.symbols

+6-4
Original file line numberDiff line numberDiff line change
@@ -52,21 +52,23 @@ declare class MyArray<T> implements Array<T> {
5252
>end : Symbol(end, Decl(implementArrayInterface.ts, 10, 25))
5353
>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22))
5454

55-
sort(compareFn?: (a: T, b: T) => number): this;
55+
sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this;
5656
>sort : Symbol(MyArray.sort, Decl(implementArrayInterface.ts, 10, 45))
5757
>compareFn : Symbol(compareFn, Decl(implementArrayInterface.ts, 11, 9))
5858
>a : Symbol(a, Decl(implementArrayInterface.ts, 11, 22))
5959
>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22))
60-
>b : Symbol(b, Decl(implementArrayInterface.ts, 11, 27))
60+
>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22))
61+
>b : Symbol(b, Decl(implementArrayInterface.ts, 11, 57))
62+
>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22))
6163
>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22))
6264

6365
splice(start: number): T[];
64-
>splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 51), Decl(implementArrayInterface.ts, 12, 31))
66+
>splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 111), Decl(implementArrayInterface.ts, 12, 31))
6567
>start : Symbol(start, Decl(implementArrayInterface.ts, 12, 11))
6668
>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22))
6769

6870
splice(start: number, deleteCount: number, ...items: T[]): T[];
69-
>splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 51), Decl(implementArrayInterface.ts, 12, 31))
71+
>splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 111), Decl(implementArrayInterface.ts, 12, 31))
7072
>start : Symbol(start, Decl(implementArrayInterface.ts, 13, 11))
7173
>deleteCount : Symbol(deleteCount, Decl(implementArrayInterface.ts, 13, 25))
7274
>items : Symbol(items, Decl(implementArrayInterface.ts, 13, 46))

tests/baselines/reference/implementArrayInterface.types

+5-5
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ declare class MyArray<T> implements Array<T> {
3838
>start : number
3939
>end : number
4040

41-
sort(compareFn?: (a: T, b: T) => number): this;
42-
>sort : (compareFn?: (a: T, b: T) => number) => this
43-
>compareFn : (a: T, b: T) => number
44-
>a : T
45-
>b : T
41+
sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this;
42+
>sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => this
43+
>compareFn : (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number
44+
>a : T extends undefined ? never : T
45+
>b : T extends undefined ? never : T
4646

4747
splice(start: number): T[];
4848
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }

tests/baselines/reference/restInvalidArgumentType.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
7171
>p1 : T
7272

7373
var {...r2} = p2; // OK
74-
>r2 : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray<T>[]): T[]; concat(...items: (T | ConcatArray<T>)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T, b: T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[]; every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
74+
>r2 : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray<T>[]): T[]; concat(...items: (T | ConcatArray<T>)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[]; every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
7575
>p2 : T[]
7676

7777
var {...r3} = t; // Error, generic type paramter

tests/baselines/reference/spreadInvalidArgumentType.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ function f<T extends { b: string }>(p1: T, p2: T[]) {
7373
>p1 : T
7474

7575
var o2 = { ...p2 }; // OK
76-
>o2 : { [x: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray<T>[]): T[]; concat(...items: (T | ConcatArray<T>)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T, b: T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[]; every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
77-
>{ ...p2 } : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray<T>[]): T[]; concat(...items: (T | ConcatArray<T>)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T, b: T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[]; every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
76+
>o2 : { [x: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray<T>[]): T[]; concat(...items: (T | ConcatArray<T>)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[]; every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
77+
>{ ...p2 } : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray<T>[]): T[]; concat(...items: (T | ConcatArray<T>)[]): T[]; join(separator?: string): string; reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): T[]; splice(start: number, deleteCount?: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; indexOf(searchElement: T, fromIndex?: number): number; lastIndexOf(searchElement: T, fromIndex?: number): number; every<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): this is S[]; every(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; some(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): boolean; forEach(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void; map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter<S extends T>(predicate: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; filter(predicate: (value: T, index: number, array: T[]) => unknown, thisArg?: any): T[]; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T): T; reduceRight(callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue: T): T; reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
7878
>p2 : T[]
7979

8080
var o3 = { ...t }; // OK, generic type paramter

tests/baselines/reference/staticAnonymousTypeNotReferencingTypeParameter.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -565,17 +565,17 @@ class ListWrapper {
565565

566566
l.sort(compareFn);
567567
>l.sort(compareFn) : T[]
568-
>l.sort : (compareFn?: (a: T, b: T) => number) => T[]
568+
>l.sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[]
569569
>l : T[]
570-
>sort : (compareFn?: (a: T, b: T) => number) => T[]
570+
>sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[]
571571
>compareFn : (a: T, b: T) => number
572572

573573
} else {
574574
l.sort();
575575
>l.sort() : T[]
576-
>l.sort : (compareFn?: (a: T, b: T) => number) => T[]
576+
>l.sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[]
577577
>l : T[]
578-
>sort : (compareFn?: (a: T, b: T) => number) => T[]
578+
>sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[]
579579
}
580580
}
581581
static toString<T>(dit: typeof ListWrapper, l: T[]): string { return l.toString(); }

tests/cases/compiler/implementArrayInterface.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ declare class MyArray<T> implements Array<T> {
99
reverse(): T[];
1010
shift(): T;
1111
slice(start?: number, end?: number): T[];
12-
sort(compareFn?: (a: T, b: T) => number): this;
12+
sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this;
1313
splice(start: number): T[];
1414
splice(start: number, deleteCount: number, ...items: T[]): T[];
1515
unshift(...items: T[]): number;

0 commit comments

Comments
 (0)