From a4bf3470084b61fb1cf22ca426c303e3ee823678 Mon Sep 17 00:00:00 2001 From: Brooke Hatton Date: Wed, 30 Dec 2020 10:50:28 +0000 Subject: [PATCH] Array.prototype.sort - remove the need for compareFn to handle undefined values. Fixes #41708 --- src/lib/es5.d.ts | 2 +- tests/baselines/reference/implementArrayInterface.js | 2 +- .../reference/implementArrayInterface.symbols | 10 ++++++---- .../baselines/reference/implementArrayInterface.types | 10 +++++----- .../baselines/reference/restInvalidArgumentType.types | 2 +- .../reference/spreadInvalidArgumentType.types | 4 ++-- ...taticAnonymousTypeNotReferencingTypeParameter.types | 8 ++++---- tests/cases/compiler/implementArrayInterface.ts | 2 +- 8 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index 461d98977730d..7c9f1ee664851 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1267,7 +1267,7 @@ interface Array { * [11,2,22,1].sort((a, b) => a - b) * ``` */ - sort(compareFn?: (a: T, b: T) => number): this; + sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this; /** * Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements. * @param start The zero-based location in the array from which to start removing elements. diff --git a/tests/baselines/reference/implementArrayInterface.js b/tests/baselines/reference/implementArrayInterface.js index 733a861071bae..d769b2ac895d4 100644 --- a/tests/baselines/reference/implementArrayInterface.js +++ b/tests/baselines/reference/implementArrayInterface.js @@ -10,7 +10,7 @@ declare class MyArray implements Array { reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; - sort(compareFn?: (a: T, b: T) => number): this; + sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this; splice(start: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number; diff --git a/tests/baselines/reference/implementArrayInterface.symbols b/tests/baselines/reference/implementArrayInterface.symbols index 4df065b57732a..4f7495182c810 100644 --- a/tests/baselines/reference/implementArrayInterface.symbols +++ b/tests/baselines/reference/implementArrayInterface.symbols @@ -52,21 +52,23 @@ declare class MyArray implements Array { >end : Symbol(end, Decl(implementArrayInterface.ts, 10, 25)) >T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22)) - sort(compareFn?: (a: T, b: T) => number): this; + sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this; >sort : Symbol(MyArray.sort, Decl(implementArrayInterface.ts, 10, 45)) >compareFn : Symbol(compareFn, Decl(implementArrayInterface.ts, 11, 9)) >a : Symbol(a, Decl(implementArrayInterface.ts, 11, 22)) >T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22)) ->b : Symbol(b, Decl(implementArrayInterface.ts, 11, 27)) +>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22)) +>b : Symbol(b, Decl(implementArrayInterface.ts, 11, 57)) +>T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22)) >T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22)) splice(start: number): T[]; ->splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 51), Decl(implementArrayInterface.ts, 12, 31)) +>splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 111), Decl(implementArrayInterface.ts, 12, 31)) >start : Symbol(start, Decl(implementArrayInterface.ts, 12, 11)) >T : Symbol(T, Decl(implementArrayInterface.ts, 0, 22)) splice(start: number, deleteCount: number, ...items: T[]): T[]; ->splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 51), Decl(implementArrayInterface.ts, 12, 31)) +>splice : Symbol(MyArray.splice, Decl(implementArrayInterface.ts, 11, 111), Decl(implementArrayInterface.ts, 12, 31)) >start : Symbol(start, Decl(implementArrayInterface.ts, 13, 11)) >deleteCount : Symbol(deleteCount, Decl(implementArrayInterface.ts, 13, 25)) >items : Symbol(items, Decl(implementArrayInterface.ts, 13, 46)) diff --git a/tests/baselines/reference/implementArrayInterface.types b/tests/baselines/reference/implementArrayInterface.types index 4d0a012a17f5e..f2e2ec5a5d8cc 100644 --- a/tests/baselines/reference/implementArrayInterface.types +++ b/tests/baselines/reference/implementArrayInterface.types @@ -38,11 +38,11 @@ declare class MyArray implements Array { >start : number >end : number - sort(compareFn?: (a: T, b: T) => number): this; ->sort : (compareFn?: (a: T, b: T) => number) => this ->compareFn : (a: T, b: T) => number ->a : T ->b : T + sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this; +>sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => this +>compareFn : (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number +>a : T extends undefined ? never : T +>b : T extends undefined ? never : T splice(start: number): T[]; >splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; } diff --git a/tests/baselines/reference/restInvalidArgumentType.types b/tests/baselines/reference/restInvalidArgumentType.types index 0e44cdfe95ccb..5a4da97c5f663 100644 --- a/tests/baselines/reference/restInvalidArgumentType.types +++ b/tests/baselines/reference/restInvalidArgumentType.types @@ -71,7 +71,7 @@ function f(p1: T, p2: T[]) { >p1 : T var {...r2} = p2; // OK ->r2 : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): 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(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(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(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(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(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } +>r2 : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): 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(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(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(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(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(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } >p2 : T[] var {...r3} = t; // Error, generic type paramter diff --git a/tests/baselines/reference/spreadInvalidArgumentType.types b/tests/baselines/reference/spreadInvalidArgumentType.types index 7698e240abbc3..2f89b78f52294 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.types +++ b/tests/baselines/reference/spreadInvalidArgumentType.types @@ -73,8 +73,8 @@ function f(p1: T, p2: T[]) { >p1 : T var o2 = { ...p2 }; // OK ->o2 : { [x: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): 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(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(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(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(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(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } ->{ ...p2 } : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): 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(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(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(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(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(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } +>o2 : { [x: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): 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(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(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(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(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(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } +>{ ...p2 } : { [n: number]: T; length: number; toString(): string; toLocaleString(): string; pop(): T; push(...items: T[]): number; concat(...items: ConcatArray[]): T[]; concat(...items: (T | ConcatArray)[]): 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(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(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]; filter(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(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(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; } >p2 : T[] var o3 = { ...t }; // OK, generic type paramter diff --git a/tests/baselines/reference/staticAnonymousTypeNotReferencingTypeParameter.types b/tests/baselines/reference/staticAnonymousTypeNotReferencingTypeParameter.types index cd907c26ec802..2c5eb4f9f684a 100644 --- a/tests/baselines/reference/staticAnonymousTypeNotReferencingTypeParameter.types +++ b/tests/baselines/reference/staticAnonymousTypeNotReferencingTypeParameter.types @@ -565,17 +565,17 @@ class ListWrapper { l.sort(compareFn); >l.sort(compareFn) : T[] ->l.sort : (compareFn?: (a: T, b: T) => number) => T[] +>l.sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[] >l : T[] ->sort : (compareFn?: (a: T, b: T) => number) => T[] +>sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[] >compareFn : (a: T, b: T) => number } else { l.sort(); >l.sort() : T[] ->l.sort : (compareFn?: (a: T, b: T) => number) => T[] +>l.sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[] >l : T[] ->sort : (compareFn?: (a: T, b: T) => number) => T[] +>sort : (compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number) => T[] } } static toString(dit: typeof ListWrapper, l: T[]): string { return l.toString(); } diff --git a/tests/cases/compiler/implementArrayInterface.ts b/tests/cases/compiler/implementArrayInterface.ts index 79ba68bdc4279..6b2e0f9aace4f 100644 --- a/tests/cases/compiler/implementArrayInterface.ts +++ b/tests/cases/compiler/implementArrayInterface.ts @@ -9,7 +9,7 @@ declare class MyArray implements Array { reverse(): T[]; shift(): T; slice(start?: number, end?: number): T[]; - sort(compareFn?: (a: T, b: T) => number): this; + sort(compareFn?: (a: T extends undefined ? never : T, b: T extends undefined ? never : T) => number): this; splice(start: number): T[]; splice(start: number, deleteCount: number, ...items: T[]): T[]; unshift(...items: T[]): number;