Skip to content
14 changes: 14 additions & 0 deletions src/lib/es2015.iterable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ interface Array<T> {
}

interface ArrayConstructor {
isArray<T>(arg: T): arg is
T extends any ?
(
true extends false & T ? Extract<any[], T> :
T extends string | readonly any[] ? never :
T extends ArrayLike<infer U> | Iterable<infer U> ? Extract<U[], T> :
never
) | (
true extends false & T ? never :
{} extends Required<T> ? T & any[] :
Extract<T, readonly any[]>
)
: never;

/**
* Creates an array from an iterable object.
* @param iterable An iterable object to convert to an array.
Expand Down
14 changes: 13 additions & 1 deletion src/lib/es5.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,19 @@ interface ArrayConstructor {
(arrayLength?: number): any[];
<T>(arrayLength: number): T[];
<T>(...items: T[]): T[];
isArray(arg: any): arg is any[];
isArray<T>(arg: T): arg is
T extends any ?
(
true extends false & T ? Extract<any[], T> :
T extends string | readonly any[] ? never :
T extends ArrayLike<infer U> ? Extract<U[], T> :
never
) | (
true extends false & T ? never :
{} extends Required<T> ? T & any[] :
Extract<T, readonly any[]>
)
: never;
readonly prototype: any[];
}

Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/arrayDestructuringInSwitch1.types
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ export function evaluate(expression: Expression): boolean {

if (Array.isArray(expression)) {
>Array.isArray(expression) : boolean
>Array.isArray : (arg: any) => arg is any[]
>Array.isArray : <T>(arg: T) => arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>isArray : <T>(arg: T) => arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never
>expression : Expression

const [operator, ...operands] = expression;
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/arrayTypeOfTypeOf.types
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ var xs2: typeof Array;
>Array : ArrayConstructor

var xs3: typeof Array<number>;
>xs3 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>xs3 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array : ArrayConstructor

var xs4: typeof Array<typeof x>;
>xs4 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>xs4 : { (arrayLength: number): number[]; (...items: number[]): number[]; new (arrayLength: number): number[]; new (...items: number[]): number[]; isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array : ArrayConstructor
>x : number

Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ export const updateIfChanged = <T>(t: T) => {
>Object.assign : Symbol(ObjectConstructor.assign, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Object : Symbol(Object, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>assign : Symbol(ObjectConstructor.assign, Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --))
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --))
>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
>u : Symbol(u, Decl(declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.ts, 7, 23))
>u : Symbol(u, Decl(declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.ts, 7, 23))
>[key] : Symbol([key], Decl(declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.ts, 12, 80))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ export const updateIfChanged = <T>(t: T) => {
>assign : { <T extends {}, U>(target: T, source: U): T & U; <T extends {}, U, V>(target: T, source1: U, source2: V): T & U & V; <T extends {}, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W; (target: object, ...sources: any[]): any; }
>Array.isArray(u) ? [] : {} : undefined[] | {}
>Array.isArray(u) : boolean
>Array.isArray : (arg: any) => arg is any[]
>Array.isArray : { <T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; <T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> | Iterable<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; }
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>isArray : { <T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; <T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> | Iterable<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; }
>u : U
>[] : undefined[]
>{} : {}
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/fixSignatureCaching.types
Original file line number Diff line number Diff line change
Expand Up @@ -1109,9 +1109,9 @@ define(function () {
>Array : ArrayConstructor

Array.isArray : function (value) { return Object.prototype.toString.call(value) === '[object Array]'; };
>Array.isArray : (arg: any) => arg is any[]
>Array.isArray : <T>(arg: T) => arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>isArray : <T>(arg: T) => arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never
>function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (value: any) => boolean
>value : any
>Object.prototype.toString.call(value) === '[object Array]' : boolean
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/instantiationExpressions.types
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ function f2() {
>Array : ArrayConstructor

const A1 = Array<string>; // new (...) => string[]
>A1 : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>Array<string> : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>A1 : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array<string> : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array : ArrayConstructor

const A2 = Array<string, number>; // Error
>A2 : { isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>Array<string, number> : { isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>A2 : { isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array<string, number> : { isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array : ArrayConstructor
}

Expand All @@ -76,11 +76,11 @@ type T20 = typeof Array<>; // Error
>Array : ArrayConstructor

type T21 = typeof Array<string>; // new (...) => string[]
>T21 : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>T21 : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array : ArrayConstructor

type T22 = typeof Array<string, number>; // Error
>T22 : { isArray(arg: any): arg is any[]; readonly prototype: any[]; }
>T22 : { isArray<T>(arg: T): arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never; readonly prototype: any[]; }
>Array : ArrayConstructor

declare class C<T> {
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/isArray.types
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ var maybeArray: number | number[];

if (Array.isArray(maybeArray)) {
>Array.isArray(maybeArray) : boolean
>Array.isArray : (arg: any) => arg is any[]
>Array.isArray : <T>(arg: T) => arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never
>Array : ArrayConstructor
>isArray : (arg: any) => arg is any[]
>isArray : <T>(arg: T) => arg is T extends any ? (true extends false & T ? Extract<any[], T> : T extends string | readonly any[] ? never : T extends ArrayLike<infer U> ? Extract<U[], T> : never) | (true extends false & T ? never : {} extends Required<T> ? T & any[] : Extract<T, readonly any[]>) : never
>maybeArray : number | number[]

maybeArray.length; // OK
Expand Down
107 changes: 107 additions & 0 deletions tests/baselines/reference/isArrayConformance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
//// [isArrayConformance.ts]
function f1(a: any) {
if (Array.isArray(a)) {
a; // Expected: any[]
}
}

function f2(a: unknown) {
if (Array.isArray(a)) {
a; // Expected: any[]
}
}

function f3(a: string | readonly string[] | number[]) {
if (Array.isArray(a)) {
var b: readonly string[] | number[] = a; // OK
a[0]; // Expected: string | number
}
}

function f4<T extends string | readonly string[] | number[]>(a: T) {
if (Array.isArray(a)) {
var b: readonly string[] | number[] = a; // OK
a[0]; // Expected: string | number
}
}

// Repro from #41808

function f5<T extends string | undefined | string[]>(a: T) {
if (Array.isArray(a)) {
a[0]; // Expected: string
}
}

function f6(a: (number[] | null | "loading")[]) {
a.filter(Array.isArray); // Expected: number[][]
}

function f7(a: {} | null) {
if (Array.isArray(a)) {
a; // Expected: any[]
}
}

function f8<T extends ArrayLike<number> | Iterable<boolean> | readonly string[] | null>(a: T) {
if (Array.isArray(a)) {
var b: readonly string[] | number[] | boolean[] = a; // OK
a[0]; // Expected: string | number | boolean
}
}

function f9(a: number | null) {
if (Array.isArray(a)) {
a; // Expected: never
}
}


//// [isArrayConformance.js]
function f1(a) {
if (Array.isArray(a)) {
a; // Expected: any[]
}
}
function f2(a) {
if (Array.isArray(a)) {
a; // Expected: any[]
}
}
function f3(a) {
if (Array.isArray(a)) {
var b = a; // OK
a[0]; // Expected: string | number
}
}
function f4(a) {
if (Array.isArray(a)) {
var b = a; // OK
a[0]; // Expected: string | number
}
}
// Repro from #41808
function f5(a) {
if (Array.isArray(a)) {
a[0]; // Expected: string
}
}
function f6(a) {
a.filter(Array.isArray); // Expected: number[][]
}
function f7(a) {
if (Array.isArray(a)) {
a; // Expected: any[]
}
}
function f8(a) {
if (Array.isArray(a)) {
var b = a; // OK
a[0]; // Expected: string | number | boolean
}
}
function f9(a) {
if (Array.isArray(a)) {
a; // Expected: never
}
}
Loading