From 262660dec2ad41df7ee1f7c07098b5449f1fb1f1 Mon Sep 17 00:00:00 2001 From: Jack Bates Date: Thu, 26 Sep 2019 14:41:04 -0700 Subject: [PATCH 1/2] Fix unsound Array.flatMap() typings --- src/lib/es2019.array.d.ts | 8 ++++---- tests/baselines/reference/arrayFlatMap.types | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/lib/es2019.array.d.ts b/src/lib/es2019.array.d.ts index 9e3e04e58158d..494bfa6b1fbc3 100644 --- a/src/lib/es2019.array.d.ts +++ b/src/lib/es2019.array.d.ts @@ -11,9 +11,9 @@ interface ReadonlyArray { * thisArg is omitted, undefined is used as the this value. */ flatMap ( - callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray, + callback: (this: This, value: T, index: number, array: T[]) => U, thisArg?: This - ): U[] + ): (U extends readonly (infer V)[] ? V : U)[]; /** @@ -125,9 +125,9 @@ interface Array { * thisArg is omitted, undefined is used as the this value. */ flatMap ( - callback: (this: This, value: T, index: number, array: T[]) => U | ReadonlyArray, + callback: (this: This, value: T, index: number, array: T[]) => U, thisArg?: This - ): U[] + ): (U extends readonly (infer V)[] ? V : U)[]; /** * Returns a new array with all sub-array elements concatenated into it recursively up to the diff --git a/tests/baselines/reference/arrayFlatMap.types b/tests/baselines/reference/arrayFlatMap.types index 631ae04ef982f..3f1e3f863ded1 100644 --- a/tests/baselines/reference/arrayFlatMap.types +++ b/tests/baselines/reference/arrayFlatMap.types @@ -9,17 +9,17 @@ const readonlyArray: ReadonlyArray = []; array.flatMap((): ReadonlyArray => []); // ok >array.flatMap((): ReadonlyArray => []) : number[] ->array.flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[] +>array.flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => (U extends readonly (infer V)[] ? V : U)[] >array : number[] ->flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[] +>flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => (U extends readonly (infer V)[] ? V : U)[] >(): ReadonlyArray => [] : () => readonly number[] >[] : undefined[] readonlyArray.flatMap((): ReadonlyArray => []); // ok >readonlyArray.flatMap((): ReadonlyArray => []) : number[] ->readonlyArray.flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[] +>readonlyArray.flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => (U extends readonly (infer V)[] ? V : U)[] >readonlyArray : readonly number[] ->flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[] +>flatMap : (callback: (this: This, value: number, index: number, array: number[]) => U, thisArg?: This) => (U extends readonly (infer V)[] ? V : U)[] >(): ReadonlyArray => [] : () => readonly number[] >[] : undefined[] From 307822396425a5d1996691d773a4145ecb43781e Mon Sep 17 00:00:00 2001 From: Jack Bates Date: Thu, 26 Sep 2019 16:04:39 -0700 Subject: [PATCH 2/2] Add tests --- tests/baselines/reference/arrayFlatMap.js | 8 ++++++++ tests/baselines/reference/arrayFlatMap.symbols | 11 +++++++++++ tests/baselines/reference/arrayFlatMap.types | 17 +++++++++++++++++ tests/cases/compiler/arrayFlatMap.ts | 5 +++++ 4 files changed, 41 insertions(+) diff --git a/tests/baselines/reference/arrayFlatMap.js b/tests/baselines/reference/arrayFlatMap.js index 3c35cedc1f3be..0344776d9c245 100644 --- a/tests/baselines/reference/arrayFlatMap.js +++ b/tests/baselines/reference/arrayFlatMap.js @@ -3,6 +3,11 @@ const array: number[] = []; const readonlyArray: ReadonlyArray = []; array.flatMap((): ReadonlyArray => []); // ok readonlyArray.flatMap((): ReadonlyArray => []); // ok + +// #19535 + +const [x] = [""].flatMap(undefined as () => string[] | string[][]); +x == ""; //// [arrayFlatMap.js] @@ -10,3 +15,6 @@ var array = []; var readonlyArray = []; array.flatMap(function () { return []; }); // ok readonlyArray.flatMap(function () { return []; }); // ok +// #19535 +var x = [""].flatMap(undefined)[0]; +x == ""; diff --git a/tests/baselines/reference/arrayFlatMap.symbols b/tests/baselines/reference/arrayFlatMap.symbols index b3a8d55721acd..2c08f13dc12d3 100644 --- a/tests/baselines/reference/arrayFlatMap.symbols +++ b/tests/baselines/reference/arrayFlatMap.symbols @@ -18,3 +18,14 @@ readonlyArray.flatMap((): ReadonlyArray => []); // ok >flatMap : Symbol(ReadonlyArray.flatMap, Decl(lib.es2019.array.d.ts, --, --)) >ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2016.array.include.d.ts, --, --), Decl(lib.es2019.array.d.ts, --, --)) +// #19535 + +const [x] = [""].flatMap(undefined as () => string[] | string[][]); +>x : Symbol(x, Decl(arrayFlatMap.ts, 7, 7)) +>[""].flatMap : Symbol(Array.flatMap, Decl(lib.es2019.array.d.ts, --, --)) +>flatMap : Symbol(Array.flatMap, Decl(lib.es2019.array.d.ts, --, --)) +>undefined : Symbol(undefined) + +x == ""; +>x : Symbol(x, Decl(arrayFlatMap.ts, 7, 7)) + diff --git a/tests/baselines/reference/arrayFlatMap.types b/tests/baselines/reference/arrayFlatMap.types index 3f1e3f863ded1..10a9931a70d71 100644 --- a/tests/baselines/reference/arrayFlatMap.types +++ b/tests/baselines/reference/arrayFlatMap.types @@ -23,3 +23,20 @@ readonlyArray.flatMap((): ReadonlyArray => []); // ok >(): ReadonlyArray => [] : () => readonly number[] >[] : undefined[] +// #19535 + +const [x] = [""].flatMap(undefined as () => string[] | string[][]); +>x : string | string[] +>[""].flatMap(undefined as () => string[] | string[][]) : (string | string[])[] +>[""].flatMap : (callback: (this: This, value: string, index: number, array: string[]) => U, thisArg?: This) => (U extends readonly (infer V)[] ? V : U)[] +>[""] : string[] +>"" : "" +>flatMap : (callback: (this: This, value: string, index: number, array: string[]) => U, thisArg?: This) => (U extends readonly (infer V)[] ? V : U)[] +>undefined as () => string[] | string[][] : () => string[] | string[][] +>undefined : undefined + +x == ""; +>x == "" : boolean +>x : string | string[] +>"" : "" + diff --git a/tests/cases/compiler/arrayFlatMap.ts b/tests/cases/compiler/arrayFlatMap.ts index 98f84e7877363..a02998b9a607f 100644 --- a/tests/cases/compiler/arrayFlatMap.ts +++ b/tests/cases/compiler/arrayFlatMap.ts @@ -4,3 +4,8 @@ const array: number[] = []; const readonlyArray: ReadonlyArray = []; array.flatMap((): ReadonlyArray => []); // ok readonlyArray.flatMap((): ReadonlyArray => []); // ok + +// #19535 + +const [x] = [""].flatMap(undefined as () => string[] | string[][]); +x == "";