Merge pull request #20467 from Kovensky/array-from-union-fix

Accept Iterable|ArrayLike union in Array.from, add tests
This commit is contained in:
Daniel Rosenwasser 2017-12-07 17:22:05 -08:00 committed by GitHub
commit 8d209a3672
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 487 additions and 18 deletions

View file

@ -52,7 +52,7 @@ interface ArrayConstructor {
* Creates an array from an iterable object.
* @param iterable An iterable object to convert to an array.
*/
from<T>(iterable: Iterable<T>): T[];
from<T>(iterable: Iterable<T> | ArrayLike<T>): 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<T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[];
from<T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[];
}
interface ReadonlyArray<T> {

View file

@ -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<A> = { 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<T>,
// even when the type is written as : Iterable<T>|ArrayLike<T>
function getEither<T> (in1: Iterable<T>, in2: ArrayLike<T>) {
return Math.random() > 0.5 ? in1 : in2;
}

View file

@ -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<A> = { 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<T>,
// even when the type is written as : Iterable<T>|ArrayLike<T>
function getEither<T> (in1: Iterable<T>, in2: ArrayLike<T>) {
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<T>,
// even when the type is written as : Iterable<T>|ArrayLike<T>
function getEither(in1, in2) {
return Math.random() > 0.5 ? in1 : in2;
}

View file

@ -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<A> = { 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<T>,
// even when the type is written as : Iterable<T>|ArrayLike<T>
function getEither<T> (in1: Iterable<T>, in2: ArrayLike<T>) {
>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))
}

View file

@ -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<A> = { length: 0 };
>inputALike : ArrayLike<A>
>ArrayLike : ArrayLike<T>
>A : A
>{ length: 0 } : { length: number; }
>length : number
>0 : 0
const inputARand = getEither(inputA, inputALike);
>inputARand : ArrayLike<A> | Iterable<A>
>getEither(inputA, inputALike) : ArrayLike<A> | Iterable<A>
>getEither : <T>(in1: Iterable<T>, in2: ArrayLike<T>) => Iterable<T> | ArrayLike<T>
>inputA : A[]
>inputALike : ArrayLike<A>
const result1: A[] = Array.from(inputA);
>result1 : A[]
>A : A
>Array.from(inputA) : A[]
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, 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 : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputA.values() : IterableIterator<A>
>inputA.values : () => IterableIterator<A>
>inputA : A[]
>values : () => IterableIterator<A>
const result3: B[] = Array.from(inputA.values()); // expect error
>result3 : B[]
>B : B
>Array.from(inputA.values()) : A[]
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputA.values() : IterableIterator<A>
>inputA.values : () => IterableIterator<A>
>inputA : A[]
>values : () => IterableIterator<A>
const result4: A[] = Array.from(inputB, ({ b }): A => ({ a: b }));
>result4 : A[]
>A : A
>Array.from(inputB, ({ b }): A => ({ a: b })) : A[]
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, 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 : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputALike : ArrayLike<A>
const result6: B[] = Array.from(inputALike); // expect error
>result6 : B[]
>B : B
>Array.from(inputALike) : A[]
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputALike : ArrayLike<A>
const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a }));
>result7 : B[]
>B : B
>Array.from(inputALike, ({ a }): B => ({ b: a })) : B[]
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputALike : ArrayLike<A>
>({ 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 : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputARand : ArrayLike<A> | Iterable<A>
const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a }));
>result9 : B[]
>B : B
>Array.from(inputARand, ({ a }): B => ({ b: a })) : B[]
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>inputARand : ArrayLike<A> | Iterable<A>
>({ 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<T>,
// even when the type is written as : Iterable<T>|ArrayLike<T>
function getEither<T> (in1: Iterable<T>, in2: ArrayLike<T>) {
>getEither : <T>(in1: Iterable<T>, in2: ArrayLike<T>) => Iterable<T> | ArrayLike<T>
>T : T
>in1 : Iterable<T>
>Iterable : Iterable<T>
>T : T
>in2 : ArrayLike<T>
>ArrayLike : ArrayLike<T>
>T : T
return Math.random() > 0.5 ? in1 : in2;
>Math.random() > 0.5 ? in1 : in2 : Iterable<T> | ArrayLike<T>
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
>in1 : Iterable<T>
>in2 : ArrayLike<T>
}

View file

@ -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: (Nominal<"A", string>[] | ReadonlyArray<Nominal<"A", string>>)[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | Nominal<"A", string>[] | ReadonlyArray<Nominal<"A", string>>)[]): Nominal<"A", string>[]; }
>Array.from(a) : Nominal<"A", string>[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>a : Set<Nominal<"A", string>>
>concat : { (...items: (Nominal<"A", string>[] | ReadonlyArray<Nominal<"A", string>>)[]): Nominal<"A", string>[]; (...items: (Nominal<"A", string> | Nominal<"A", string>[] | ReadonlyArray<Nominal<"A", string>>)[]): Nominal<"A", string>[]; }
>Array.from(b) : Nominal<"A", string>[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>b : Set<Nominal<"A", string>>
// Simpler repro

View file

@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) {
return Array.from(arguments);
>Array.from(arguments) : any[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>arguments : IArguments
}

View file

@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) {
return Array.from(arguments);
>Array.from(arguments) : any[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>arguments : IArguments
}

View file

@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) {
return Array.from(arguments);
>Array.from(arguments) : any[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>arguments : IArguments
}

View file

@ -8,9 +8,9 @@ function f(x: number, y: number, z: number) {
return Array.from(arguments);
>Array.from(arguments) : any[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>arguments : IArguments
}

View file

@ -100,9 +100,9 @@ f2(Array.from([0]), [], (a1, a2) => a1 - a2);
>f2(Array.from([0]), [], (a1, a2) => a1 - a2) : void
>f2 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
>Array.from([0]) : number[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, 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 : <a>(as1: a[], as2: a[], cmp: (a1: a, a2: a) => number) => void
>Array.from([]) : never[]
>Array.from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array.from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>Array : ArrayConstructor
>from : { <T>(iterable: Iterable<T>): T[]; <T, U>(iterable: Iterable<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>from : { <T>(iterable: Iterable<T> | ArrayLike<T>): T[]; <T, U>(iterable: Iterable<T> | ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; <T>(arrayLike: ArrayLike<T>): T[]; <T, U>(arrayLike: ArrayLike<T>, mapfn: (v: T, k: number) => U, thisArg?: any): U[]; }
>[] : never[]
>[0] : number[]
>0 : 0

View file

@ -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<A> = { 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<T>,
// even when the type is written as : Iterable<T>|ArrayLike<T>
function getEither<T> (in1: Iterable<T>, in2: ArrayLike<T>) {
return Math.random() > 0.5 ? in1 : in2;
}