Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib Fix Part 6/6 – Array.isArray #50454

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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