diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index f1fb454f980b1..35dfffe991670 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -56,6 +56,20 @@ interface Array { } interface ArrayConstructor { + isArray(arg: T): arg is + T extends any ? + ( + true extends false & T ? Extract : + T extends string | readonly any[] ? never : + T extends ArrayLike | Iterable ? Extract : + never + ) | ( + true extends false & T ? never : + {} extends Required ? T & any[] : + Extract + ) + : never; + /** * Creates an array from an iterable object. * @param iterable An iterable object to convert to an array. diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts index a74b3cb4c2111..d83dc3ff207f0 100644 --- a/src/lib/es5.d.ts +++ b/src/lib/es5.d.ts @@ -1471,7 +1471,19 @@ interface ArrayConstructor { (arrayLength?: number): any[]; (arrayLength: number): T[]; (...items: T[]): T[]; - isArray(arg: any): arg is any[]; + isArray(arg: T): arg is + T extends any ? + ( + true extends false & T ? Extract : + T extends string | readonly any[] ? never : + T extends ArrayLike ? Extract : + never + ) | ( + true extends false & T ? never : + {} extends Required ? T & any[] : + Extract + ) + : never; readonly prototype: any[]; } diff --git a/tests/baselines/reference/arrayDestructuringInSwitch1.types b/tests/baselines/reference/arrayDestructuringInSwitch1.types index 56d48f6a30075..2bf90094e06fd 100644 --- a/tests/baselines/reference/arrayDestructuringInSwitch1.types +++ b/tests/baselines/reference/arrayDestructuringInSwitch1.types @@ -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 : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >expression : Expression const [operator, ...operands] = expression; diff --git a/tests/baselines/reference/arrayTypeOfTypeOf.types b/tests/baselines/reference/arrayTypeOfTypeOf.types index 60eec5fbba21b..06aa6bf7ff069 100644 --- a/tests/baselines/reference/arrayTypeOfTypeOf.types +++ b/tests/baselines/reference/arrayTypeOfTypeOf.types @@ -14,11 +14,11 @@ var xs2: typeof Array; >Array : ArrayConstructor var xs3: typeof Array; ->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(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } >Array : ArrayConstructor var xs4: typeof Array; ->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(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } >Array : ArrayConstructor >x : number diff --git a/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.symbols b/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.symbols index 08c4eccca0829..7f9e9c7f2b38a 100644 --- a/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.symbols +++ b/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.symbols @@ -79,9 +79,9 @@ export const updateIfChanged = (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)) diff --git a/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types b/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types index 4e4bf5b76933a..7c963a7e36ab3 100644 --- a/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types +++ b/tests/baselines/reference/declarationsWithRecursiveInternalTypesProduceUniqueTypeParams.types @@ -67,9 +67,9 @@ export const updateIfChanged = (t: T) => { >assign : { (target: T, source: U): T & U; (target: T, source1: U, source2: V): T & U & V; (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 : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } >u : U >[] : undefined[] >{} : {} diff --git a/tests/baselines/reference/fixSignatureCaching.types b/tests/baselines/reference/fixSignatureCaching.types index 0a0d657a64d10..340be93100909 100644 --- a/tests/baselines/reference/fixSignatureCaching.types +++ b/tests/baselines/reference/fixSignatureCaching.types @@ -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 : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >function (value) { return Object.prototype.toString.call(value) === '[object Array]'; } : (value: any) => boolean >value : any >Object.prototype.toString.call(value) === '[object Array]' : boolean diff --git a/tests/baselines/reference/instantiationExpressions.types b/tests/baselines/reference/instantiationExpressions.types index 75fe72fc441bc..dca0c32382e77 100644 --- a/tests/baselines/reference/instantiationExpressions.types +++ b/tests/baselines/reference/instantiationExpressions.types @@ -61,13 +61,13 @@ function f2() { >Array : ArrayConstructor const A1 = Array; // 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 : { (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(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } +>Array : { (arrayLength: number): string[]; (...items: string[]): string[]; new (arrayLength: number): string[]; new (...items: string[]): string[]; isArray(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } >Array : ArrayConstructor const A2 = Array; // Error ->A2 : { isArray(arg: any): arg is any[]; readonly prototype: any[]; } ->Array : { isArray(arg: any): arg is any[]; readonly prototype: any[]; } +>A2 : { isArray(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } +>Array : { isArray(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } >Array : ArrayConstructor } @@ -76,11 +76,11 @@ type T20 = typeof Array<>; // Error >Array : ArrayConstructor type T21 = typeof Array; // 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(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } >Array : ArrayConstructor type T22 = typeof Array; // Error ->T22 : { isArray(arg: any): arg is any[]; readonly prototype: any[]; } +>T22 : { isArray(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; } >Array : ArrayConstructor declare class C { diff --git a/tests/baselines/reference/isArray.types b/tests/baselines/reference/isArray.types index bc452b12bef01..ba56644f4843e 100644 --- a/tests/baselines/reference/isArray.types +++ b/tests/baselines/reference/isArray.types @@ -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 : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >maybeArray : number | number[] maybeArray.length; // OK diff --git a/tests/baselines/reference/isArrayConformance.js b/tests/baselines/reference/isArrayConformance.js new file mode 100644 index 0000000000000..b71fcd5ea35f7 --- /dev/null +++ b/tests/baselines/reference/isArrayConformance.js @@ -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(a: T) { + if (Array.isArray(a)) { + var b: readonly string[] | number[] = a; // OK + a[0]; // Expected: string | number + } +} + +// Repro from #41808 + +function f5(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 | Iterable | 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 + } +} diff --git a/tests/baselines/reference/isArrayConformance.symbols b/tests/baselines/reference/isArrayConformance.symbols new file mode 100644 index 0000000000000..14c7a7e332eb6 --- /dev/null +++ b/tests/baselines/reference/isArrayConformance.symbols @@ -0,0 +1,156 @@ +=== tests/cases/compiler/isArrayConformance.ts === +function f1(a: any) { +>f1 : Symbol(f1, Decl(isArrayConformance.ts, 0, 0)) +>a : Symbol(a, Decl(isArrayConformance.ts, 0, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 0, 12)) + + a; // Expected: any[] +>a : Symbol(a, Decl(isArrayConformance.ts, 0, 12)) + } +} + +function f2(a: unknown) { +>f2 : Symbol(f2, Decl(isArrayConformance.ts, 4, 1)) +>a : Symbol(a, Decl(isArrayConformance.ts, 6, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 6, 12)) + + a; // Expected: any[] +>a : Symbol(a, Decl(isArrayConformance.ts, 6, 12)) + } +} + +function f3(a: string | readonly string[] | number[]) { +>f3 : Symbol(f3, Decl(isArrayConformance.ts, 10, 1)) +>a : Symbol(a, Decl(isArrayConformance.ts, 12, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 12, 12)) + + var b: readonly string[] | number[] = a; // OK +>b : Symbol(b, Decl(isArrayConformance.ts, 14, 5)) +>a : Symbol(a, Decl(isArrayConformance.ts, 12, 12)) + + a[0]; // Expected: string | number +>a : Symbol(a, Decl(isArrayConformance.ts, 12, 12)) + } +} + +function f4(a: T) { +>f4 : Symbol(f4, Decl(isArrayConformance.ts, 17, 1)) +>T : Symbol(T, Decl(isArrayConformance.ts, 19, 12)) +>a : Symbol(a, Decl(isArrayConformance.ts, 19, 61)) +>T : Symbol(T, Decl(isArrayConformance.ts, 19, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 19, 61)) + + var b: readonly string[] | number[] = a; // OK +>b : Symbol(b, Decl(isArrayConformance.ts, 21, 5)) +>a : Symbol(a, Decl(isArrayConformance.ts, 19, 61)) + + a[0]; // Expected: string | number +>a : Symbol(a, Decl(isArrayConformance.ts, 19, 61)) + } +} + +// Repro from #41808 + +function f5(a: T) { +>f5 : Symbol(f5, Decl(isArrayConformance.ts, 24, 1)) +>T : Symbol(T, Decl(isArrayConformance.ts, 28, 12)) +>a : Symbol(a, Decl(isArrayConformance.ts, 28, 53)) +>T : Symbol(T, Decl(isArrayConformance.ts, 28, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 28, 53)) + + a[0]; // Expected: string +>a : Symbol(a, Decl(isArrayConformance.ts, 28, 53)) + } +} + +function f6(a: (number[] | null | "loading")[]) { +>f6 : Symbol(f6, Decl(isArrayConformance.ts, 32, 1)) +>a : Symbol(a, Decl(isArrayConformance.ts, 34, 12)) + + a.filter(Array.isArray); // Expected: number[][] +>a.filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 34, 12)) +>filter : Symbol(Array.filter, Decl(lib.es5.d.ts, --, --), 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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +} + +function f7(a: {} | null) { +>f7 : Symbol(f7, Decl(isArrayConformance.ts, 36, 1)) +>a : Symbol(a, Decl(isArrayConformance.ts, 38, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 38, 12)) + + a; // Expected: any[] +>a : Symbol(a, Decl(isArrayConformance.ts, 38, 12)) + } +} + +function f8 | Iterable | readonly string[] | null>(a: T) { +>f8 : Symbol(f8, Decl(isArrayConformance.ts, 42, 1)) +>T : Symbol(T, Decl(isArrayConformance.ts, 44, 12)) +>ArrayLike : Symbol(ArrayLike, Decl(lib.es5.d.ts, --, --)) +>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 44, 88)) +>T : Symbol(T, Decl(isArrayConformance.ts, 44, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 44, 88)) + + var b: readonly string[] | number[] | boolean[] = a; // OK +>b : Symbol(b, Decl(isArrayConformance.ts, 46, 5)) +>a : Symbol(a, Decl(isArrayConformance.ts, 44, 88)) + + a[0]; // Expected: string | number | boolean +>a : Symbol(a, Decl(isArrayConformance.ts, 44, 88)) + } +} + +function f9(a: number | null) { +>f9 : Symbol(f9, Decl(isArrayConformance.ts, 49, 1)) +>a : Symbol(a, Decl(isArrayConformance.ts, 51, 12)) + + if (Array.isArray(a)) { +>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, --, --) ... and 4 more) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance.ts, 51, 12)) + + a; // Expected: never +>a : Symbol(a, Decl(isArrayConformance.ts, 51, 12)) + } +} + diff --git a/tests/baselines/reference/isArrayConformance.types b/tests/baselines/reference/isArrayConformance.types new file mode 100644 index 0000000000000..8b2db137a2323 --- /dev/null +++ b/tests/baselines/reference/isArrayConformance.types @@ -0,0 +1,169 @@ +=== tests/cases/compiler/isArrayConformance.ts === +function f1(a: any) { +>f1 : (a: any) => void +>a : any + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : any + + a; // Expected: any[] +>a : any[] + } +} + +function f2(a: unknown) { +>f2 : (a: unknown) => void +>a : unknown + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : unknown + + a; // Expected: any[] +>a : any[] + } +} + +function f3(a: string | readonly string[] | number[]) { +>f3 : (a: string | readonly string[] | number[]) => void +>a : string | readonly string[] | number[] + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : string | readonly string[] | number[] + + var b: readonly string[] | number[] = a; // OK +>b : readonly string[] | number[] +>a : readonly string[] | number[] + + a[0]; // Expected: string | number +>a[0] : string | number +>a : readonly string[] | number[] +>0 : 0 + } +} + +function f4(a: T) { +>f4 : (a: T) => void +>a : T + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : T + + var b: readonly string[] | number[] = a; // OK +>b : readonly string[] | number[] +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never + + a[0]; // Expected: string | number +>a[0] : string | number +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>0 : 0 + } +} + +// Repro from #41808 + +function f5(a: T) { +>f5 : (a: T) => void +>a : T + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : T + + a[0]; // Expected: string +>a[0] : string +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>0 : 0 + } +} + +function f6(a: (number[] | null | "loading")[]) { +>f6 : (a: (number[] | null | "loading")[]) => void +>a : (number[] | "loading")[] +>null : null + + a.filter(Array.isArray); // Expected: number[][] +>a.filter(Array.isArray) : any[][] +>a.filter : { (predicate: (value: number[] | "loading", index: number, array: (number[] | "loading")[]) => value is S, thisArg?: any): S[]; (predicate: (value: number[] | "loading", index: number, array: (number[] | "loading")[]) => unknown, thisArg?: any): (number[] | "loading")[]; } +>a : (number[] | "loading")[] +>filter : { (predicate: (value: number[] | "loading", index: number, array: (number[] | "loading")[]) => value is S, thisArg?: any): S[]; (predicate: (value: number[] | "loading", index: number, array: (number[] | "loading")[]) => unknown, thisArg?: any): (number[] | "loading")[]; } +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +} + +function f7(a: {} | null) { +>f7 : (a: {} | null) => void +>a : {} +>null : null + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : {} + + a; // Expected: any[] +>a : any[] + } +} + +function f8 | Iterable | readonly string[] | null>(a: T) { +>f8 : | Iterable>(a: T) => void +>null : null +>a : T + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : T + + var b: readonly string[] | number[] | boolean[] = a; // OK +>b : readonly string[] | number[] | boolean[] +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never + + a[0]; // Expected: string | number | boolean +>a[0] : string | number | boolean +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>0 : 0 + } +} + +function f9(a: number | null) { +>f9 : (a: number | null) => void +>a : number +>null : null + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>Array : ArrayConstructor +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } +>a : number + + a; // Expected: never +>a : never + } +} + diff --git a/tests/baselines/reference/isArrayConformance2.js b/tests/baselines/reference/isArrayConformance2.js new file mode 100644 index 0000000000000..bb73838def727 --- /dev/null +++ b/tests/baselines/reference/isArrayConformance2.js @@ -0,0 +1,113 @@ +//// [isArrayConformance2.ts] +function fa(a: [number, ...string[]] | readonly [boolean, boolean] | null) { + if (Array.isArray(a)) { + a; // Expected: [number, ...string[]] | readonly [boolean, boolean] + } +} + +function fb(a: T) { + if (Array.isArray(a)) { + var b: [number, ...string[]] | readonly [boolean, boolean] = a; // OK + a[0]; // Expected: number | boolean + } +} + +function fc(obj: T, prop: P) { + const value = obj[prop]; + if (Array.isArray(value)) { + value.length; // OK + } +} + +function fd(value: Record) { + if (Array.isArray(value)) { + value.length; // OK + } +} + +function fe(data: T) { + if (Array.isArray(data)) { + for (const key in data) { // OK + const value = data[key]; + if (Array.isArray(value)) { + value.length; // OK + } + } + } +} + +function ff(a: T | T[]): T[] { + return Array.isArray(a) ? a : [a]; // OK +} + +function fg(arr1: T[], arr2: T[]) { + for (let i = 0; i < arr1.length && i < arr2.length; i++) { + const item1 = arr1[i]; + const item2 = arr2[i]; + if (Array.isArray(item1) && Array.isArray(item2)) { + fg(item1, item2); // OK + } + } +} + +function fh(...args: [] | [attributes: ({ $: string } & Partial>) | Record, children?: any[]] | [children: any[]]) { + if (Array.isArray(args[0])) { + const children: (Record | HTMLElement)[] = args[0]; // OK + } +} + + +//// [isArrayConformance2.js] +function fa(a) { + if (Array.isArray(a)) { + a; // Expected: [number, ...string[]] | readonly [boolean, boolean] + } +} +function fb(a) { + if (Array.isArray(a)) { + var b = a; // OK + a[0]; // Expected: number | boolean + } +} +function fc(obj, prop) { + var value = obj[prop]; + if (Array.isArray(value)) { + value.length; // OK + } +} +function fd(value) { + if (Array.isArray(value)) { + value.length; // OK + } +} +function fe(data) { + if (Array.isArray(data)) { + for (var key in data) { // OK + var value = data[key]; + if (Array.isArray(value)) { + value.length; // OK + } + } + } +} +function ff(a) { + return Array.isArray(a) ? a : [a]; // OK +} +function fg(arr1, arr2) { + for (var i = 0; i < arr1.length && i < arr2.length; i++) { + var item1 = arr1[i]; + var item2 = arr2[i]; + if (Array.isArray(item1) && Array.isArray(item2)) { + fg(item1, item2); // OK + } + } +} +function fh() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + if (Array.isArray(args[0])) { + var children = args[0]; // OK + } +} diff --git a/tests/baselines/reference/isArrayConformance2.symbols b/tests/baselines/reference/isArrayConformance2.symbols new file mode 100644 index 0000000000000..e5c0f2cfa1eef --- /dev/null +++ b/tests/baselines/reference/isArrayConformance2.symbols @@ -0,0 +1,210 @@ +=== tests/cases/compiler/isArrayConformance2.ts === +function fa(a: [number, ...string[]] | readonly [boolean, boolean] | null) { +>fa : Symbol(fa, Decl(isArrayConformance2.ts, 0, 0)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 0, 12)) + + if (Array.isArray(a)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 0, 12)) + + a; // Expected: [number, ...string[]] | readonly [boolean, boolean] +>a : Symbol(a, Decl(isArrayConformance2.ts, 0, 12)) + } +} + +function fb(a: T) { +>fb : Symbol(fb, Decl(isArrayConformance2.ts, 4, 1)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 6, 12)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 6, 82)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 6, 12)) + + if (Array.isArray(a)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 6, 82)) + + var b: [number, ...string[]] | readonly [boolean, boolean] = a; // OK +>b : Symbol(b, Decl(isArrayConformance2.ts, 8, 5)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 6, 82)) + + a[0]; // Expected: number | boolean +>a : Symbol(a, Decl(isArrayConformance2.ts, 6, 82)) +>0 : Symbol(0) + } +} + +function fc(obj: T, prop: P) { +>fc : Symbol(fc, Decl(isArrayConformance2.ts, 11, 1)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 13, 12)) +>P : Symbol(P, Decl(isArrayConformance2.ts, 13, 14)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 13, 12)) +>obj : Symbol(obj, Decl(isArrayConformance2.ts, 13, 34)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 13, 12)) +>prop : Symbol(prop, Decl(isArrayConformance2.ts, 13, 41)) +>P : Symbol(P, Decl(isArrayConformance2.ts, 13, 14)) + + const value = obj[prop]; +>value : Symbol(value, Decl(isArrayConformance2.ts, 14, 6)) +>obj : Symbol(obj, Decl(isArrayConformance2.ts, 13, 34)) +>prop : Symbol(prop, Decl(isArrayConformance2.ts, 13, 41)) + + if (Array.isArray(value)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 14, 6)) + + value.length; // OK +>value.length : Symbol(length, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 14, 6)) +>length : Symbol(length, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + } +} + +function fd(value: Record) { +>fd : Symbol(fd, Decl(isArrayConformance2.ts, 18, 1)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 20, 12)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + if (Array.isArray(value)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 20, 12)) + + value.length; // OK +>value.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 20, 12)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + } +} + +function fe(data: T) { +>fe : Symbol(fe, Decl(isArrayConformance2.ts, 24, 1)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 26, 12)) +>data : Symbol(data, Decl(isArrayConformance2.ts, 26, 15)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 26, 12)) + + if (Array.isArray(data)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>data : Symbol(data, Decl(isArrayConformance2.ts, 26, 15)) + + for (const key in data) { // OK +>key : Symbol(key, Decl(isArrayConformance2.ts, 28, 12)) +>data : Symbol(data, Decl(isArrayConformance2.ts, 26, 15)) + + const value = data[key]; +>value : Symbol(value, Decl(isArrayConformance2.ts, 29, 8)) +>data : Symbol(data, Decl(isArrayConformance2.ts, 26, 15)) +>key : Symbol(key, Decl(isArrayConformance2.ts, 28, 12)) + + if (Array.isArray(value)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 29, 8)) + + value.length; // OK +>value.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>value : Symbol(value, Decl(isArrayConformance2.ts, 29, 8)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) + } + } + } +} + +function ff(a: T | T[]): T[] { +>ff : Symbol(ff, Decl(isArrayConformance2.ts, 35, 1)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 37, 12)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 37, 27)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 37, 12)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 37, 12)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 37, 12)) + + return Array.isArray(a) ? a : [a]; // OK +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 37, 27)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 37, 27)) +>a : Symbol(a, Decl(isArrayConformance2.ts, 37, 27)) +} + +function fg(arr1: T[], arr2: T[]) { +>fg : Symbol(fg, Decl(isArrayConformance2.ts, 39, 1)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 41, 12)) +>arr1 : Symbol(arr1, Decl(isArrayConformance2.ts, 41, 27)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 41, 12)) +>arr2 : Symbol(arr2, Decl(isArrayConformance2.ts, 41, 37)) +>T : Symbol(T, Decl(isArrayConformance2.ts, 41, 12)) + + for (let i = 0; i < arr1.length && i < arr2.length; i++) { +>i : Symbol(i, Decl(isArrayConformance2.ts, 42, 9)) +>i : Symbol(i, Decl(isArrayConformance2.ts, 42, 9)) +>arr1.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>arr1 : Symbol(arr1, Decl(isArrayConformance2.ts, 41, 27)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>i : Symbol(i, Decl(isArrayConformance2.ts, 42, 9)) +>arr2.length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>arr2 : Symbol(arr2, Decl(isArrayConformance2.ts, 41, 37)) +>length : Symbol(Array.length, Decl(lib.es5.d.ts, --, --)) +>i : Symbol(i, Decl(isArrayConformance2.ts, 42, 9)) + + const item1 = arr1[i]; +>item1 : Symbol(item1, Decl(isArrayConformance2.ts, 43, 7)) +>arr1 : Symbol(arr1, Decl(isArrayConformance2.ts, 41, 27)) +>i : Symbol(i, Decl(isArrayConformance2.ts, 42, 9)) + + const item2 = arr2[i]; +>item2 : Symbol(item2, Decl(isArrayConformance2.ts, 44, 7)) +>arr2 : Symbol(arr2, Decl(isArrayConformance2.ts, 41, 37)) +>i : Symbol(i, Decl(isArrayConformance2.ts, 42, 9)) + + if (Array.isArray(item1) && Array.isArray(item2)) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>item1 : Symbol(item1, Decl(isArrayConformance2.ts, 43, 7)) +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>item2 : Symbol(item2, Decl(isArrayConformance2.ts, 44, 7)) + + fg(item1, item2); // OK +>fg : Symbol(fg, Decl(isArrayConformance2.ts, 39, 1)) +>item1 : Symbol(item1, Decl(isArrayConformance2.ts, 43, 7)) +>item2 : Symbol(item2, Decl(isArrayConformance2.ts, 44, 7)) + } + } +} + +function fh(...args: [] | [attributes: ({ $: string } & Partial>) | Record, children?: any[]] | [children: any[]]) { +>fh : Symbol(fh, Decl(isArrayConformance2.ts, 49, 1)) +>args : Symbol(args, Decl(isArrayConformance2.ts, 51, 12)) +>$ : Symbol($, Decl(isArrayConformance2.ts, 51, 41)) +>Partial : Symbol(Partial, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) + + if (Array.isArray(args[0])) { +>Array.isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>args : Symbol(args, Decl(isArrayConformance2.ts, 51, 12)) +>0 : Symbol(0) + + const children: (Record | HTMLElement)[] = args[0]; // OK +>children : Symbol(children, Decl(isArrayConformance2.ts, 53, 7)) +>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>HTMLElement : Symbol(HTMLElement, Decl(lib.dom.d.ts, --, --), Decl(lib.dom.d.ts, --, --)) +>args : Symbol(args, Decl(isArrayConformance2.ts, 51, 12)) +>0 : Symbol(0) + } +} + diff --git a/tests/baselines/reference/isArrayConformance2.types b/tests/baselines/reference/isArrayConformance2.types new file mode 100644 index 0000000000000..e6e0d6a676306 --- /dev/null +++ b/tests/baselines/reference/isArrayConformance2.types @@ -0,0 +1,215 @@ +=== tests/cases/compiler/isArrayConformance2.ts === +function fa(a: [number, ...string[]] | readonly [boolean, boolean] | null) { +>fa : (a: [number, ...string[]] | readonly [boolean, boolean] | null) => void +>a : [number, ...string[]] | readonly [boolean, boolean] +>null : null + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>a : [number, ...string[]] | readonly [boolean, boolean] + + a; // Expected: [number, ...string[]] | readonly [boolean, boolean] +>a : [number, ...string[]] | readonly [boolean, boolean] + } +} + +function fb(a: T) { +>fb : (a: T) => void +>null : null +>a : T + + if (Array.isArray(a)) { +>Array.isArray(a) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>a : T + + var b: [number, ...string[]] | readonly [boolean, boolean] = a; // OK +>b : [number, ...string[]] | readonly [boolean, boolean] +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never + + a[0]; // Expected: number | boolean +>a[0] : number | boolean +>a : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>0 : 0 + } +} + +function fc(obj: T, prop: P) { +>fc : (obj: T, prop: P) => void +>obj : T +>prop : P + + const value = obj[prop]; +>value : T[P] +>obj[prop] : T[P] +>obj : T +>prop : P + + if (Array.isArray(value)) { +>Array.isArray(value) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>value : T[P] + + value.length; // OK +>value.length : number +>value : T[P] extends any ? (true extends false & T[P] ? Extract : T[P] extends string | readonly any[] ? never : T[P] extends ArrayLike ? Extract : never) | (true extends false & T[P] ? never : {} extends Required ? T[P] & any[] : Extract) : never +>length : number + } +} + +function fd(value: Record) { +>fd : (value: Record) => void +>value : Record + + if (Array.isArray(value)) { +>Array.isArray(value) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>value : Record + + value.length; // OK +>value.length : number +>value : Record & any[] +>length : number + } +} + +function fe(data: T) { +>fe : (data: T) => void +>data : T + + if (Array.isArray(data)) { +>Array.isArray(data) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>data : T + + for (const key in data) { // OK +>key : Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never), string> +>data : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never + + const value = data[key]; +>value : any +>data[key] : any +>data : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>key : Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never), string> + + if (Array.isArray(value)) { +>Array.isArray(value) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>value : any + + value.length; // OK +>value.length : number +>value : any[] +>length : number + } + } + } +} + +function ff(a: T | T[]): T[] { +>ff : (a: T | T[]) => T[] +>a : T | T[] + + return Array.isArray(a) ? a : [a]; // OK +>Array.isArray(a) ? a : [a] : T[] | (T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never) +>Array.isArray(a) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>a : T | T[] +>a : T[] | (T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never) +>[a] : T[] +>a : T +} + +function fg(arr1: T[], arr2: T[]) { +>fg : (arr1: T[], arr2: T[]) => void +>arr1 : T[] +>arr2 : T[] + + for (let i = 0; i < arr1.length && i < arr2.length; i++) { +>i : number +>0 : 0 +>i < arr1.length && i < arr2.length : boolean +>i < arr1.length : boolean +>i : number +>arr1.length : number +>arr1 : T[] +>length : number +>i < arr2.length : boolean +>i : number +>arr2.length : number +>arr2 : T[] +>length : number +>i++ : number +>i : number + + const item1 = arr1[i]; +>item1 : T +>arr1[i] : T +>arr1 : T[] +>i : number + + const item2 = arr2[i]; +>item2 : T +>arr2[i] : T +>arr2 : T[] +>i : number + + if (Array.isArray(item1) && Array.isArray(item2)) { +>Array.isArray(item1) && Array.isArray(item2) : boolean +>Array.isArray(item1) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>item1 : T +>Array.isArray(item2) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>item2 : T + + fg(item1, item2); // OK +>fg(item1, item2) : void +>fg : (arr1: T[], arr2: T[]) => void +>item1 : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>item2 : T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never + } + } +} + +function fh(...args: [] | [attributes: ({ $: string } & Partial>) | Record, children?: any[]] | [children: any[]]) { +>fh : (...args: [] | [attributes: ({ $: string;} & Partial>) | Record, children?: any[]] | [children: any[]]) => void +>args : [] | [attributes: Record | ({ $: string; } & Partial>), children?: any[]] | [children: any[]] +>$ : string + + if (Array.isArray(args[0])) { +>Array.isArray(args[0]) : boolean +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>Array : ArrayConstructor +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>args[0] : any[] | Record | ({ $: string; } & Partial>) +>args : [] | [attributes: Record | ({ $: string; } & Partial>), children?: any[]] | [children: any[]] +>0 : 0 + + const children: (Record | HTMLElement)[] = args[0]; // OK +>children : (HTMLElement | Record)[] +>args[0] : any[] | (Record & any[]) +>args : [] | [attributes: Record | ({ $: string; } & Partial>), children?: any[]] | [children: any[]] +>0 : 0 + } +} + diff --git a/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.errors.txt b/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.errors.txt index a4729d56ef55b..fe028accbd6e2 100644 --- a/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.errors.txt +++ b/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.errors.txt @@ -1,6 +1,6 @@ -/src/a.js(10,7): error TS2417: Class static side 'typeof ElementsArray' incorrectly extends base class static side '{ isArray(arg: any): arg is any[]; readonly prototype: any[]; }'. +/src/a.js(10,7): error TS2417: Class static side 'typeof ElementsArray' incorrectly extends base class static side '{ isArray(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; }'. Types of property 'isArray' are incompatible. - Type '(arg: any) => boolean' is not assignable to type '(arg: any) => arg is any[]'. + Type '(arg: any) => boolean' is not assignable to type '(arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never'. Signature '(arg: any): boolean' must be a type predicate. @@ -16,9 +16,9 @@ // GH#46468 class ElementsArray extends Array { ~~~~~~~~~~~~~ -!!! error TS2417: Class static side 'typeof ElementsArray' incorrectly extends base class static side '{ isArray(arg: any): arg is any[]; readonly prototype: any[]; }'. +!!! error TS2417: Class static side 'typeof ElementsArray' incorrectly extends base class static side '{ isArray(arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; readonly prototype: any[]; }'. !!! error TS2417: Types of property 'isArray' are incompatible. -!!! error TS2417: Type '(arg: any) => boolean' is not assignable to type '(arg: any) => arg is any[]'. +!!! error TS2417: Type '(arg: any) => boolean' is not assignable to type '(arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never'. !!! error TS2417: Signature '(arg: any): boolean' must be a type predicate. static { const superisArray = super.isArray; diff --git a/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.types b/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.types index bbb41f4ea47fd..0aa4d36f18f2e 100644 --- a/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.types +++ b/tests/baselines/reference/javascriptThisAssignmentInStaticBlock.types @@ -25,17 +25,17 @@ class ElementsArray extends Array { static { const superisArray = super.isArray; ->superisArray : (arg: any) => arg is any[] ->super.isArray : (arg: any) => arg is any[] +>superisArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never +>super.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >super : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never const customIsArray = (arg)=> superisArray(arg); >customIsArray : (arg: any) => boolean >(arg)=> superisArray(arg) : (arg: any) => boolean >arg : any >superisArray(arg) : boolean ->superisArray : (arg: any) => arg is any[] +>superisArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >arg : any this.isArray = customIsArray; diff --git a/tests/baselines/reference/literalFreshnessPropagationOnNarrowing.types b/tests/baselines/reference/literalFreshnessPropagationOnNarrowing.types index fd3858baebc68..be4032c30f240 100644 --- a/tests/baselines/reference/literalFreshnessPropagationOnNarrowing.types +++ b/tests/baselines/reference/literalFreshnessPropagationOnNarrowing.types @@ -66,9 +66,9 @@ function f2() { >a4 : (string | false) | (string | false)[] >Array.isArray(elOrA) ? elOrA : [elOrA] : (string | false)[] >Array.isArray(elOrA) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >elOrA : (string | false) | (string | false)[] >elOrA : (string | false)[] >[elOrA] : (string | false)[] @@ -83,9 +83,9 @@ function f2() { >...Array.isArray(elOrA) ? elOrA : [elOrA] : string | false >Array.isArray(elOrA) ? elOrA : [elOrA] : (string | false)[] >Array.isArray(elOrA) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >elOrA : (string | false) | (string | false)[] >elOrA : (string | false)[] >[elOrA] : (string | false)[] diff --git a/tests/baselines/reference/malformedTags.types b/tests/baselines/reference/malformedTags.types index c3af959586790..a70d4053b1ad0 100644 --- a/tests/baselines/reference/malformedTags.types +++ b/tests/baselines/reference/malformedTags.types @@ -6,7 +6,7 @@ */ var isArray = Array.isArray; >isArray : Function ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never diff --git a/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.symbols b/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.symbols index 8b7fcfebae44f..268a658b8f0c7 100644 --- a/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.symbols +++ b/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.symbols @@ -91,9 +91,9 @@ function testFunc() { const reversedVal1 = val1.slice().reverse(); >reversedVal1 : Symbol(reversedVal1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 29, 15)) >val1.slice().reverse : Symbol(Array.reverse, Decl(lib.es5.d.ts, --, --)) ->val1.slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) +>val1.slice : Symbol(ReadonlyArray.slice, Decl(lib.es5.d.ts, --, --)) >val1 : Symbol(val1, Decl(narrowingAssignmentReadonlyRespectsAssertion.ts, 26, 26)) ->slice : Symbol(Array.slice, Decl(lib.es5.d.ts, --, --)) +>slice : Symbol(ReadonlyArray.slice, Decl(lib.es5.d.ts, --, --)) >reverse : Symbol(Array.reverse, Decl(lib.es5.d.ts, --, --)) console.log(reversedVal1); diff --git a/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.types b/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.types index 9fd13d661027a..8b3ca612352f2 100644 --- a/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.types +++ b/tests/baselines/reference/narrowingAssignmentReadonlyRespectsAssertion.types @@ -100,28 +100,28 @@ function testFunc() { if (Array.isArray(val1)) { >Array.isArray(val1) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >val1 : string | number | readonly (string | number)[] // This should retain val1 as being an array const reversedVal1 = val1.slice().reverse(); ->reversedVal1 : any[] ->val1.slice().reverse() : any[] ->val1.slice().reverse : () => any[] ->val1.slice() : any[] ->val1.slice : (start?: number, end?: number) => any[] ->val1 : any[] ->slice : (start?: number, end?: number) => any[] ->reverse : () => any[] +>reversedVal1 : (string | number)[] +>val1.slice().reverse() : (string | number)[] +>val1.slice().reverse : () => (string | number)[] +>val1.slice() : (string | number)[] +>val1.slice : (start?: number, end?: number) => (string | number)[] +>val1 : readonly (string | number)[] +>slice : (start?: number, end?: number) => (string | number)[] +>reverse : () => (string | number)[] console.log(reversedVal1); >console.log(reversedVal1) : void >console.log : (...data: any[]) => void >console : Console >log : (...data: any[]) => void ->reversedVal1 : any[] +>reversedVal1 : (string | number)[] } else { console.log(val1); @@ -129,7 +129,7 @@ function testFunc() { >console.log : (...data: any[]) => void >console : Console >log : (...data: any[]) => void ->val1 : string | number | readonly (string | number)[] +>val1 : string | number } console.log(val2); >console.log(val2) : void diff --git a/tests/baselines/reference/noIterationTypeErrorsInCFA.symbols b/tests/baselines/reference/noIterationTypeErrorsInCFA.symbols index 5dafdb84061b2..71f10aeb05422 100644 --- a/tests/baselines/reference/noIterationTypeErrorsInCFA.symbols +++ b/tests/baselines/reference/noIterationTypeErrorsInCFA.symbols @@ -12,9 +12,9 @@ export function doRemove(dds: F | F[]) { >F : Symbol(F, Decl(noIterationTypeErrorsInCFA.ts, 0, 0)) if (!Array.isArray(dds)) { ->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, --, --) ... and 4 more) ->isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --)) +>isArray : Symbol(ArrayConstructor.isArray, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) >dds : Symbol(dds, Decl(noIterationTypeErrorsInCFA.ts, 3, 25)) dds = [dds] diff --git a/tests/baselines/reference/noIterationTypeErrorsInCFA.types b/tests/baselines/reference/noIterationTypeErrorsInCFA.types index 9d0122627ffae..4cd8a23be5ebe 100644 --- a/tests/baselines/reference/noIterationTypeErrorsInCFA.types +++ b/tests/baselines/reference/noIterationTypeErrorsInCFA.types @@ -10,9 +10,9 @@ export function doRemove(dds: F | F[]) { if (!Array.isArray(dds)) { >!Array.isArray(dds) : boolean >Array.isArray(dds) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : { (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; (arg: T): arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike | Iterable ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never; } >dds : F | F[] dds = [dds] diff --git a/tests/baselines/reference/parserharness.types b/tests/baselines/reference/parserharness.types index 498e9bf7ea7ce..070dd35e8740f 100644 --- a/tests/baselines/reference/parserharness.types +++ b/tests/baselines/reference/parserharness.types @@ -3068,13 +3068,13 @@ module Harness { >(Array.isArray && Array.isArray(arg)) || arg instanceof Array : boolean >(Array.isArray && Array.isArray(arg)) : boolean >Array.isArray && Array.isArray(arg) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array.isArray(arg) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >arg : any >arg instanceof Array : boolean >arg : any diff --git a/tests/baselines/reference/partiallyDiscriminantedUnions.types b/tests/baselines/reference/partiallyDiscriminantedUnions.types index bc2ee1bf23586..0c65501f95dd7 100644 --- a/tests/baselines/reference/partiallyDiscriminantedUnions.types +++ b/tests/baselines/reference/partiallyDiscriminantedUnions.types @@ -77,9 +77,9 @@ function isShape(s : Shapes): s is Shape { return !Array.isArray(s); >!Array.isArray(s) : boolean >Array.isArray(s) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >s : Shapes } diff --git a/tests/baselines/reference/spreadBooleanRespectsFreshness.types b/tests/baselines/reference/spreadBooleanRespectsFreshness.types index 3ccc42b24e3ce..72819dcff94bc 100644 --- a/tests/baselines/reference/spreadBooleanRespectsFreshness.types +++ b/tests/baselines/reference/spreadBooleanRespectsFreshness.types @@ -22,9 +22,9 @@ foo1 = [...Array.isArray(foo2) ? foo2 : [foo2]]; >...Array.isArray(foo2) ? foo2 : [foo2] : FooBase >Array.isArray(foo2) ? foo2 : [foo2] : FooArray >Array.isArray(foo2) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >foo2 : Foo >foo2 : FooArray >[foo2] : FooBase[] diff --git a/tests/baselines/reference/unknownControlFlow.types b/tests/baselines/reference/unknownControlFlow.types index 24cbd3b162850..655fa30d3b1b7 100644 --- a/tests/baselines/reference/unknownControlFlow.types +++ b/tests/baselines/reference/unknownControlFlow.types @@ -660,14 +660,14 @@ function deepEquals(a: T, b: T): boolean { if (Array.isArray(a) || Array.isArray(b)) { >Array.isArray(a) || Array.isArray(b) : boolean >Array.isArray(a) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >a : T & object >Array.isArray(b) : boolean ->Array.isArray : (arg: any) => arg is any[] +>Array.isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >Array : ArrayConstructor ->isArray : (arg: any) => arg is any[] +>isArray : (arg: T) => arg is T extends any ? (true extends false & T ? Extract : T extends string | readonly any[] ? never : T extends ArrayLike ? Extract : never) | (true extends false & T ? never : {} extends Required ? T & any[] : Extract) : never >b : T & object return false; diff --git a/tests/cases/compiler/isArrayConformance.ts b/tests/cases/compiler/isArrayConformance.ts new file mode 100644 index 0000000000000..b9a0c64d3d7b8 --- /dev/null +++ b/tests/cases/compiler/isArrayConformance.ts @@ -0,0 +1,58 @@ +// @lib: esnext + +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(a: T) { + if (Array.isArray(a)) { + var b: readonly string[] | number[] = a; // OK + a[0]; // Expected: string | number + } +} + +// Repro from #41808 + +function f5(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 | Iterable | 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 + } +} diff --git a/tests/cases/compiler/isArrayConformance2.ts b/tests/cases/compiler/isArrayConformance2.ts new file mode 100644 index 0000000000000..40647d02bf9a2 --- /dev/null +++ b/tests/cases/compiler/isArrayConformance2.ts @@ -0,0 +1,56 @@ +function fa(a: [number, ...string[]] | readonly [boolean, boolean] | null) { + if (Array.isArray(a)) { + a; // Expected: [number, ...string[]] | readonly [boolean, boolean] + } +} + +function fb(a: T) { + if (Array.isArray(a)) { + var b: [number, ...string[]] | readonly [boolean, boolean] = a; // OK + a[0]; // Expected: number | boolean + } +} + +function fc(obj: T, prop: P) { + const value = obj[prop]; + if (Array.isArray(value)) { + value.length; // OK + } +} + +function fd(value: Record) { + if (Array.isArray(value)) { + value.length; // OK + } +} + +function fe(data: T) { + if (Array.isArray(data)) { + for (const key in data) { // OK + const value = data[key]; + if (Array.isArray(value)) { + value.length; // OK + } + } + } +} + +function ff(a: T | T[]): T[] { + return Array.isArray(a) ? a : [a]; // OK +} + +function fg(arr1: T[], arr2: T[]) { + for (let i = 0; i < arr1.length && i < arr2.length; i++) { + const item1 = arr1[i]; + const item2 = arr2[i]; + if (Array.isArray(item1) && Array.isArray(item2)) { + fg(item1, item2); // OK + } + } +} + +function fh(...args: [] | [attributes: ({ $: string } & Partial>) | Record, children?: any[]] | [children: any[]]) { + if (Array.isArray(args[0])) { + const children: (Record | HTMLElement)[] = args[0]; // OK + } +}