From c894eebe51f55a720e4f01901227f05af7cba7f5 Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Tue, 5 Dec 2017 14:37:51 +0900 Subject: [PATCH] Accept Iterable|ArrayLike union in Array.from, test --- src/lib/es2015.iterable.d.ts | 4 +- .../baselines/reference/arrayFrom.errors.txt | 46 +++++ tests/baselines/reference/arrayFrom.js | 66 +++++++ tests/baselines/reference/arrayFrom.symbols | 147 +++++++++++++++ tests/baselines/reference/arrayFrom.types | 176 ++++++++++++++++++ .../intersectionTypeInference3.types | 8 +- ...eLibrary_NoErrorDuplicateLibOptions1.types | 4 +- ...eLibrary_NoErrorDuplicateLibOptions2.types | 4 +- ...dularizeLibrary_TargetES5UsingES6Lib.types | 4 +- ...dularizeLibrary_TargetES6UsingES6Lib.types | 4 +- .../baselines/reference/neverInference.types | 8 +- tests/cases/compiler/arrayFrom.ts | 34 ++++ 12 files changed, 487 insertions(+), 18 deletions(-) create mode 100644 tests/baselines/reference/arrayFrom.errors.txt create mode 100644 tests/baselines/reference/arrayFrom.js create mode 100644 tests/baselines/reference/arrayFrom.symbols create mode 100644 tests/baselines/reference/arrayFrom.types create mode 100644 tests/cases/compiler/arrayFrom.ts diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index f3024bc334..26722b5ab2 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -52,7 +52,7 @@ interface ArrayConstructor { * Creates an array from an iterable object. * @param iterable An iterable object to convert to an array. */ - from(iterable: Iterable): T[]; + from(iterable: Iterable | ArrayLike): T[]; /** * Creates an array from an iterable object. @@ -60,7 +60,7 @@ interface ArrayConstructor { * @param mapfn A mapping function to call on every element of the array. * @param thisArg Value of 'this' used to invoke the mapfn. */ - from(iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; + from(iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } interface ReadonlyArray { diff --git a/tests/baselines/reference/arrayFrom.errors.txt b/tests/baselines/reference/arrayFrom.errors.txt new file mode 100644 index 0000000000..896125ee1c --- /dev/null +++ b/tests/baselines/reference/arrayFrom.errors.txt @@ -0,0 +1,46 @@ +tests/cases/compiler/arrayFrom.ts(19,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'. + Type 'A' is not assignable to type 'B'. + Property 'b' is missing in type 'A'. +tests/cases/compiler/arrayFrom.ts(22,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'. + + +==== tests/cases/compiler/arrayFrom.ts (2 errors) ==== + // Tests fix for #20432, ensures Array.from accepts all valid inputs + // Also tests for #19682 + + interface A { + a: string; + } + + interface B { + b: string; + } + + const inputA: A[] = []; + const inputB: B[] = []; + const inputALike: ArrayLike = { length: 0 }; + const inputARand = getEither(inputA, inputALike); + + const result1: A[] = Array.from(inputA); + const result2: A[] = Array.from(inputA.values()); + const result3: B[] = Array.from(inputA.values()); // expect error + ~~~~~~~ +!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'. +!!! error TS2322: Type 'A' is not assignable to type 'B'. +!!! error TS2322: Property 'b' is missing in type 'A'. + const result4: A[] = Array.from(inputB, ({ b }): A => ({ a: b })); + const result5: A[] = Array.from(inputALike); + const result6: B[] = Array.from(inputALike); // expect error + ~~~~~~~ +!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'. + const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); + const result8: A[] = Array.from(inputARand); + const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); + + // if this is written inline, the compiler seems to infer + // the ?: as always taking the false branch, narrowing to ArrayLike, + // even when the type is written as : Iterable|ArrayLike + function getEither (in1: Iterable, in2: ArrayLike) { + return Math.random() > 0.5 ? in1 : in2; + } + \ No newline at end of file diff --git a/tests/baselines/reference/arrayFrom.js b/tests/baselines/reference/arrayFrom.js new file mode 100644 index 0000000000..b9b7ff7526 --- /dev/null +++ b/tests/baselines/reference/arrayFrom.js @@ -0,0 +1,66 @@ +//// [arrayFrom.ts] +// Tests fix for #20432, ensures Array.from accepts all valid inputs +// Also tests for #19682 + +interface A { + a: string; +} + +interface B { + b: string; +} + +const inputA: A[] = []; +const inputB: B[] = []; +const inputALike: ArrayLike = { length: 0 }; +const inputARand = getEither(inputA, inputALike); + +const result1: A[] = Array.from(inputA); +const result2: A[] = Array.from(inputA.values()); +const result3: B[] = Array.from(inputA.values()); // expect error +const result4: A[] = Array.from(inputB, ({ b }): A => ({ a: b })); +const result5: A[] = Array.from(inputALike); +const result6: B[] = Array.from(inputALike); // expect error +const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); +const result8: A[] = Array.from(inputARand); +const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); + +// if this is written inline, the compiler seems to infer +// the ?: as always taking the false branch, narrowing to ArrayLike, +// even when the type is written as : Iterable|ArrayLike +function getEither (in1: Iterable, in2: ArrayLike) { + return Math.random() > 0.5 ? in1 : in2; +} + + +//// [arrayFrom.js] +// Tests fix for #20432, ensures Array.from accepts all valid inputs +// Also tests for #19682 +var inputA = []; +var inputB = []; +var inputALike = { length: 0 }; +var inputARand = getEither(inputA, inputALike); +var result1 = Array.from(inputA); +var result2 = Array.from(inputA.values()); +var result3 = Array.from(inputA.values()); // expect error +var result4 = Array.from(inputB, function (_a) { + var b = _a.b; + return ({ a: b }); +}); +var result5 = Array.from(inputALike); +var result6 = Array.from(inputALike); // expect error +var result7 = Array.from(inputALike, function (_a) { + var a = _a.a; + return ({ b: a }); +}); +var result8 = Array.from(inputARand); +var result9 = Array.from(inputARand, function (_a) { + var a = _a.a; + return ({ b: a }); +}); +// if this is written inline, the compiler seems to infer +// the ?: as always taking the false branch, narrowing to ArrayLike, +// even when the type is written as : Iterable|ArrayLike +function getEither(in1, in2) { + return Math.random() > 0.5 ? in1 : in2; +} diff --git a/tests/baselines/reference/arrayFrom.symbols b/tests/baselines/reference/arrayFrom.symbols new file mode 100644 index 0000000000..4a68122739 --- /dev/null +++ b/tests/baselines/reference/arrayFrom.symbols @@ -0,0 +1,147 @@ +=== tests/cases/compiler/arrayFrom.ts === +// Tests fix for #20432, ensures Array.from accepts all valid inputs +// Also tests for #19682 + +interface A { +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) + + a: string; +>a : Symbol(A.a, Decl(arrayFrom.ts, 3, 13)) +} + +interface B { +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) + + b: string; +>b : Symbol(B.b, Decl(arrayFrom.ts, 7, 13)) +} + +const inputA: A[] = []; +>inputA : Symbol(inputA, Decl(arrayFrom.ts, 11, 5)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) + +const inputB: B[] = []; +>inputB : Symbol(inputB, Decl(arrayFrom.ts, 12, 5)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) + +const inputALike: ArrayLike = { length: 0 }; +>inputALike : Symbol(inputALike, Decl(arrayFrom.ts, 13, 5)) +>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>length : Symbol(length, Decl(arrayFrom.ts, 13, 34)) + +const inputARand = getEither(inputA, inputALike); +>inputARand : Symbol(inputARand, Decl(arrayFrom.ts, 14, 5)) +>getEither : Symbol(getEither, Decl(arrayFrom.ts, 24, 70)) +>inputA : Symbol(inputA, Decl(arrayFrom.ts, 11, 5)) +>inputALike : Symbol(inputALike, Decl(arrayFrom.ts, 13, 5)) + +const result1: A[] = Array.from(inputA); +>result1 : Symbol(result1, Decl(arrayFrom.ts, 16, 5)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputA : Symbol(inputA, Decl(arrayFrom.ts, 11, 5)) + +const result2: A[] = Array.from(inputA.values()); +>result2 : Symbol(result2, Decl(arrayFrom.ts, 17, 5)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputA.values : Symbol(Array.values, Decl(lib.es2015.iterable.d.ts, --, --)) +>inputA : Symbol(inputA, Decl(arrayFrom.ts, 11, 5)) +>values : Symbol(Array.values, Decl(lib.es2015.iterable.d.ts, --, --)) + +const result3: B[] = Array.from(inputA.values()); // expect error +>result3 : Symbol(result3, Decl(arrayFrom.ts, 18, 5)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputA.values : Symbol(Array.values, Decl(lib.es2015.iterable.d.ts, --, --)) +>inputA : Symbol(inputA, Decl(arrayFrom.ts, 11, 5)) +>values : Symbol(Array.values, Decl(lib.es2015.iterable.d.ts, --, --)) + +const result4: A[] = Array.from(inputB, ({ b }): A => ({ a: b })); +>result4 : Symbol(result4, Decl(arrayFrom.ts, 19, 5)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputB : Symbol(inputB, Decl(arrayFrom.ts, 12, 5)) +>b : Symbol(b, Decl(arrayFrom.ts, 19, 42)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>a : Symbol(a, Decl(arrayFrom.ts, 19, 56)) +>b : Symbol(b, Decl(arrayFrom.ts, 19, 42)) + +const result5: A[] = Array.from(inputALike); +>result5 : Symbol(result5, Decl(arrayFrom.ts, 20, 5)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputALike : Symbol(inputALike, Decl(arrayFrom.ts, 13, 5)) + +const result6: B[] = Array.from(inputALike); // expect error +>result6 : Symbol(result6, Decl(arrayFrom.ts, 21, 5)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputALike : Symbol(inputALike, Decl(arrayFrom.ts, 13, 5)) + +const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); +>result7 : Symbol(result7, Decl(arrayFrom.ts, 22, 5)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputALike : Symbol(inputALike, Decl(arrayFrom.ts, 13, 5)) +>a : Symbol(a, Decl(arrayFrom.ts, 22, 46)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) +>b : Symbol(b, Decl(arrayFrom.ts, 22, 60)) +>a : Symbol(a, Decl(arrayFrom.ts, 22, 46)) + +const result8: A[] = Array.from(inputARand); +>result8 : Symbol(result8, Decl(arrayFrom.ts, 23, 5)) +>A : Symbol(A, Decl(arrayFrom.ts, 0, 0)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputARand : Symbol(inputARand, Decl(arrayFrom.ts, 14, 5)) + +const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); +>result9 : Symbol(result9, Decl(arrayFrom.ts, 24, 5)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) +>Array.from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>from : Symbol(ArrayConstructor.from, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>inputARand : Symbol(inputARand, Decl(arrayFrom.ts, 14, 5)) +>a : Symbol(a, Decl(arrayFrom.ts, 24, 46)) +>B : Symbol(B, Decl(arrayFrom.ts, 5, 1)) +>b : Symbol(b, Decl(arrayFrom.ts, 24, 60)) +>a : Symbol(a, Decl(arrayFrom.ts, 24, 46)) + +// if this is written inline, the compiler seems to infer +// the ?: as always taking the false branch, narrowing to ArrayLike, +// even when the type is written as : Iterable|ArrayLike +function getEither (in1: Iterable, in2: ArrayLike) { +>getEither : Symbol(getEither, Decl(arrayFrom.ts, 24, 70)) +>T : Symbol(T, Decl(arrayFrom.ts, 29, 19)) +>in1 : Symbol(in1, Decl(arrayFrom.ts, 29, 23)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) +>T : Symbol(T, Decl(arrayFrom.ts, 29, 19)) +>in2 : Symbol(in2, Decl(arrayFrom.ts, 29, 40)) +>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --)) +>T : Symbol(T, Decl(arrayFrom.ts, 29, 19)) + + return Math.random() > 0.5 ? in1 : in2; +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>in1 : Symbol(in1, Decl(arrayFrom.ts, 29, 23)) +>in2 : Symbol(in2, Decl(arrayFrom.ts, 29, 40)) +} + diff --git a/tests/baselines/reference/arrayFrom.types b/tests/baselines/reference/arrayFrom.types new file mode 100644 index 0000000000..f6a04dc442 --- /dev/null +++ b/tests/baselines/reference/arrayFrom.types @@ -0,0 +1,176 @@ +=== tests/cases/compiler/arrayFrom.ts === +// Tests fix for #20432, ensures Array.from accepts all valid inputs +// Also tests for #19682 + +interface A { +>A : A + + a: string; +>a : string +} + +interface B { +>B : B + + b: string; +>b : string +} + +const inputA: A[] = []; +>inputA : A[] +>A : A +>[] : undefined[] + +const inputB: B[] = []; +>inputB : B[] +>B : B +>[] : undefined[] + +const inputALike: ArrayLike = { length: 0 }; +>inputALike : ArrayLike +>ArrayLike : ArrayLike +>A : A +>{ length: 0 } : { length: number; } +>length : number +>0 : 0 + +const inputARand = getEither(inputA, inputALike); +>inputARand : ArrayLike | Iterable +>getEither(inputA, inputALike) : ArrayLike | Iterable +>getEither : (in1: Iterable, in2: ArrayLike) => Iterable | ArrayLike +>inputA : A[] +>inputALike : ArrayLike + +const result1: A[] = Array.from(inputA); +>result1 : A[] +>A : A +>Array.from(inputA) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputA : A[] + +const result2: A[] = Array.from(inputA.values()); +>result2 : A[] +>A : A +>Array.from(inputA.values()) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputA.values() : IterableIterator +>inputA.values : () => IterableIterator +>inputA : A[] +>values : () => IterableIterator + +const result3: B[] = Array.from(inputA.values()); // expect error +>result3 : B[] +>B : B +>Array.from(inputA.values()) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputA.values() : IterableIterator +>inputA.values : () => IterableIterator +>inputA : A[] +>values : () => IterableIterator + +const result4: A[] = Array.from(inputB, ({ b }): A => ({ a: b })); +>result4 : A[] +>A : A +>Array.from(inputB, ({ b }): A => ({ a: b })) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputB : B[] +>({ b }): A => ({ a: b }) : ({ b }: B) => A +>b : string +>A : A +>({ a: b }) : { a: string; } +>{ a: b } : { a: string; } +>a : string +>b : string + +const result5: A[] = Array.from(inputALike); +>result5 : A[] +>A : A +>Array.from(inputALike) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputALike : ArrayLike + +const result6: B[] = Array.from(inputALike); // expect error +>result6 : B[] +>B : B +>Array.from(inputALike) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputALike : ArrayLike + +const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); +>result7 : B[] +>B : B +>Array.from(inputALike, ({ a }): B => ({ b: a })) : B[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputALike : ArrayLike +>({ a }): B => ({ b: a }) : ({ a }: A) => B +>a : string +>B : B +>({ b: a }) : { b: string; } +>{ b: a } : { b: string; } +>b : string +>a : string + +const result8: A[] = Array.from(inputARand); +>result8 : A[] +>A : A +>Array.from(inputARand) : A[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputARand : ArrayLike | Iterable + +const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); +>result9 : B[] +>B : B +>Array.from(inputARand, ({ a }): B => ({ b: a })) : B[] +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array : ArrayConstructor +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>inputARand : ArrayLike | Iterable +>({ a }): B => ({ b: a }) : ({ a }: A) => B +>a : string +>B : B +>({ b: a }) : { b: string; } +>{ b: a } : { b: string; } +>b : string +>a : string + +// if this is written inline, the compiler seems to infer +// the ?: as always taking the false branch, narrowing to ArrayLike, +// even when the type is written as : Iterable|ArrayLike +function getEither (in1: Iterable, in2: ArrayLike) { +>getEither : (in1: Iterable, in2: ArrayLike) => Iterable | ArrayLike +>T : T +>in1 : Iterable +>Iterable : Iterable +>T : T +>in2 : ArrayLike +>ArrayLike : ArrayLike +>T : T + + return Math.random() > 0.5 ? in1 : in2; +>Math.random() > 0.5 ? in1 : in2 : Iterable | ArrayLike +>Math.random() > 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>in1 : Iterable +>in2 : ArrayLike +} + diff --git a/tests/baselines/reference/intersectionTypeInference3.types b/tests/baselines/reference/intersectionTypeInference3.types index 9fca37af8c..1db47a3797 100644 --- a/tests/baselines/reference/intersectionTypeInference3.types +++ b/tests/baselines/reference/intersectionTypeInference3.types @@ -34,15 +34,15 @@ const c1 = Array.from(a).concat(Array.from(b)); >Array.from(a).concat(Array.from(b)) : Nominal<"A", string>[] >Array.from(a).concat : { (...items: ReadonlyArray>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray>)[]): Nominal<"A", string>[]; } >Array.from(a) : Nominal<"A", string>[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >a : Set> >concat : { (...items: ReadonlyArray>[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | ReadonlyArray>)[]): Nominal<"A", string>[]; } >Array.from(b) : Nominal<"A", string>[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >b : Set> // Simpler repro diff --git a/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions1.types b/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions1.types index afc286ca70..20d0779621 100644 --- a/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions1.types +++ b/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions1.types @@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) { return Array.from(arguments); >Array.from(arguments) : any[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >arguments : IArguments } diff --git a/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions2.types b/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions2.types index d394c411c4..367ac41f24 100644 --- a/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions2.types +++ b/tests/baselines/reference/modularizeLibrary_NoErrorDuplicateLibOptions2.types @@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) { return Array.from(arguments); >Array.from(arguments) : any[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >arguments : IArguments } diff --git a/tests/baselines/reference/modularizeLibrary_TargetES5UsingES6Lib.types b/tests/baselines/reference/modularizeLibrary_TargetES5UsingES6Lib.types index 479747d3e0..8dc959b1af 100644 --- a/tests/baselines/reference/modularizeLibrary_TargetES5UsingES6Lib.types +++ b/tests/baselines/reference/modularizeLibrary_TargetES5UsingES6Lib.types @@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) { return Array.from(arguments); >Array.from(arguments) : any[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >arguments : IArguments } diff --git a/tests/baselines/reference/modularizeLibrary_TargetES6UsingES6Lib.types b/tests/baselines/reference/modularizeLibrary_TargetES6UsingES6Lib.types index efb2beddb4..2f1fab30cf 100644 --- a/tests/baselines/reference/modularizeLibrary_TargetES6UsingES6Lib.types +++ b/tests/baselines/reference/modularizeLibrary_TargetES6UsingES6Lib.types @@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) { return Array.from(arguments); >Array.from(arguments) : any[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >arguments : IArguments } diff --git a/tests/baselines/reference/neverInference.types b/tests/baselines/reference/neverInference.types index 2f4b9e0cc1..50deacc8c1 100644 --- a/tests/baselines/reference/neverInference.types +++ b/tests/baselines/reference/neverInference.types @@ -100,9 +100,9 @@ f2(Array.from([0]), [], (a1, a2) => a1 - a2); >f2(Array.from([0]), [], (a1, a2) => a1 - a2) : void >f2 : (as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void >Array.from([0]) : number[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >[0] : number[] >0 : 0 >[] : never[] @@ -117,9 +117,9 @@ f2(Array.from([]), [0], (a1, a2) => a1 - a2); >f2(Array.from([]), [0], (a1, a2) => a1 - a2) : void >f2 : (as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void >Array.from([]) : never[] ->Array.from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>Array.from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >Array : ArrayConstructor ->from : { (iterable: Iterable): T[]; (iterable: Iterable, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } +>from : { (iterable: Iterable | ArrayLike): T[]; (iterable: Iterable | ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; (arrayLike: ArrayLike): T[]; (arrayLike: ArrayLike, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; } >[] : never[] >[0] : number[] >0 : 0 diff --git a/tests/cases/compiler/arrayFrom.ts b/tests/cases/compiler/arrayFrom.ts new file mode 100644 index 0000000000..f0b8f5928c --- /dev/null +++ b/tests/cases/compiler/arrayFrom.ts @@ -0,0 +1,34 @@ +// @lib: es2015 + +// Tests fix for #20432, ensures Array.from accepts all valid inputs +// Also tests for #19682 + +interface A { + a: string; +} + +interface B { + b: string; +} + +const inputA: A[] = []; +const inputB: B[] = []; +const inputALike: ArrayLike = { length: 0 }; +const inputARand = getEither(inputA, inputALike); + +const result1: A[] = Array.from(inputA); +const result2: A[] = Array.from(inputA.values()); +const result3: B[] = Array.from(inputA.values()); // expect error +const result4: A[] = Array.from(inputB, ({ b }): A => ({ a: b })); +const result5: A[] = Array.from(inputALike); +const result6: B[] = Array.from(inputALike); // expect error +const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a })); +const result8: A[] = Array.from(inputARand); +const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a })); + +// if this is written inline, the compiler seems to infer +// the ?: as always taking the false branch, narrowing to ArrayLike, +// even when the type is written as : Iterable|ArrayLike +function getEither (in1: Iterable, in2: ArrayLike) { + return Math.random() > 0.5 ? in1 : in2; +}