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

Apply contextual type to empty array literals #47898

Closed
wants to merge 3 commits into from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -17007,7 +17007,10 @@ namespace ts {
case SyntaxKind.ObjectLiteralExpression:
return some((node as ObjectLiteralExpression).properties, isContextSensitive);
case SyntaxKind.ArrayLiteralExpression:
return some((node as ArrayLiteralExpression).elements, isContextSensitive);
if ((node as ArrayLiteralExpression).elements.length > 0) {
return some((node as ArrayLiteralExpression).elements, isContextSensitive);
}
return true;
case SyntaxKind.ConditionalExpression:
return isContextSensitive((node as ConditionalExpression).whenTrue) ||
isContextSensitive((node as ConditionalExpression).whenFalse);
Expand Down Expand Up @@ -27093,6 +27096,12 @@ namespace ts {
const elementTypes: Type[] = [];
const elementFlags: ElementFlags[] = [];
const contextualType = getApparentTypeOfContextualType(node);
if (elementCount === 0 && contextualType && !checkMode) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this may need to be moved lower, right below the tuple check - otherwise you'll never be able to get an empty tuple inferred via a contextual type.

const elementType = getElementTypeOfArrayType(contextualType);
if (elementType) {
return createArrayType(elementType);
}
}
const inDestructuringPattern = isAssignmentTarget(node);
const inConstContext = isConstContext(node);
let hasOmittedExpression = false;
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/arrayAssignmentTest1.types
Expand Up @@ -81,35 +81,35 @@ var f1 = function () { return new C1();}

var arr_any: any[] = [];
>arr_any : any[]
>[] : undefined[]
>[] : any[]

var arr_i1: I1[] = [];
>arr_i1 : I1[]
>[] : undefined[]
>[] : I1[]

var arr_c1: C1[] = [];
>arr_c1 : C1[]
>[] : undefined[]
>[] : C1[]

var arr_c2: C2[] = [];
>arr_c2 : C2[]
>[] : undefined[]
>[] : C2[]

var arr_i1_2: I1[] = [];
>arr_i1_2 : I1[]
>[] : undefined[]
>[] : I1[]

var arr_c1_2: C1[] = [];
>arr_c1_2 : C1[]
>[] : undefined[]
>[] : C1[]

var arr_c2_2: C2[] = [];
>arr_c2_2 : C2[]
>[] : undefined[]
>[] : C2[]

var arr_c3: C3[] = [];
>arr_c3 : C3[]
>[] : undefined[]
>[] : C3[]

var i1_error: I1 = []; // should be an error - is
>i1_error : I1
Expand Down
16 changes: 8 additions & 8 deletions tests/baselines/reference/arrayAssignmentTest2.types
Expand Up @@ -81,35 +81,35 @@ var f1 = function () { return new C1();}

var arr_any: any[] = [];
>arr_any : any[]
>[] : undefined[]
>[] : any[]

var arr_i1: I1[] = [];
>arr_i1 : I1[]
>[] : undefined[]
>[] : I1[]

var arr_c1: C1[] = [];
>arr_c1 : C1[]
>[] : undefined[]
>[] : C1[]

var arr_c2: C2[] = [];
>arr_c2 : C2[]
>[] : undefined[]
>[] : C2[]

var arr_i1_2: I1[] = [];
>arr_i1_2 : I1[]
>[] : undefined[]
>[] : I1[]

var arr_c1_2: C1[] = [];
>arr_c1_2 : C1[]
>[] : undefined[]
>[] : C1[]

var arr_c2_2: C2[] = [];
>arr_c2_2 : C2[]
>[] : undefined[]
>[] : C2[]

var arr_c3: C3[] = [];
>arr_c3 : C3[]
>[] : undefined[]
>[] : C3[]

// "clean up error" occurs at this point
arr_c3 = arr_c2_2; // should be an error - is
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/arrayAssignmentTest4.types
Expand Up @@ -32,7 +32,7 @@ var o1 = {one : 1};

var arr_any: any[] = [];
>arr_any : any[]
>[] : undefined[]
>[] : any[]

arr_any = function () { return null;} // should be an error - is
>arr_any = function () { return null;} : () => any
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/arrayConcat2.types
@@ -1,7 +1,7 @@
=== tests/cases/compiler/arrayConcat2.ts ===
var a: string[] = [];
>a : string[]
>[] : undefined[]
>[] : string[]

a.concat("hello", 'world');
>a.concat("hello", 'world') : string[]
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/arrayFlatMap.types
@@ -1,25 +1,25 @@
=== tests/cases/compiler/arrayFlatMap.ts ===
const array: number[] = [];
>array : number[]
>[] : undefined[]
>[] : number[]

const readonlyArray: ReadonlyArray<number> = [];
>readonlyArray : readonly number[]
>[] : undefined[]
>[] : number[]

array.flatMap((): ReadonlyArray<number> => []); // ok
>array.flatMap((): ReadonlyArray<number> => []) : number[]
>array.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
>array : number[]
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
>(): ReadonlyArray<number> => [] : () => ReadonlyArray<number>
>[] : undefined[]
>[] : number[]

readonlyArray.flatMap((): ReadonlyArray<number> => []); // ok
>readonlyArray.flatMap((): ReadonlyArray<number> => []) : number[]
>readonlyArray.flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
>readonlyArray : readonly number[]
>flatMap : <U, This = undefined>(callback: (this: This, value: number, index: number, array: number[]) => U | readonly U[], thisArg?: This) => U[]
>(): ReadonlyArray<number> => [] : () => ReadonlyArray<number>
>[] : undefined[]
>[] : number[]

4 changes: 2 additions & 2 deletions tests/baselines/reference/arrayFrom.types
Expand Up @@ -14,11 +14,11 @@ interface B {

const inputA: A[] = [];
>inputA : A[]
>[] : undefined[]
>[] : A[]

const inputB: B[] = [];
>inputB : B[]
>[] : undefined[]
>[] : B[]

const inputALike: ArrayLike<A> = { length: 0 };
>inputALike : ArrayLike<A>
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/arrayLiteral.types
Expand Up @@ -29,7 +29,7 @@ var y = new Array<number>();

var x2: number[] = [];
>x2 : number[]
>[] : undefined[]
>[] : number[]

var x2: number[] = new Array(1);
>x2 : number[]
Expand Down
Expand Up @@ -7,7 +7,7 @@ function panic(val: string[], ...opt: string[]) { }
panic([], 'one', 'two');
>panic([], 'one', 'two') : void
>panic : (val: string[], ...opt: string[]) => void
>[] : undefined[]
>[] : string[]
>'one' : "one"
>'two' : "two"

2 changes: 1 addition & 1 deletion tests/baselines/reference/badArraySyntax.types
Expand Up @@ -9,7 +9,7 @@ class Z {

var a1: Z[] = [];
>a1 : Z[]
>[] : undefined[]
>[] : Z[]

var a2 = new Z[];
>a2 : any
Expand Down
Expand Up @@ -20,7 +20,7 @@ function fn<T>() {

var values: ISubject<any>[] = [];
>values : ISubject<any>[]
>[] : undefined[]
>[] : ISubject<any>[]

// Hang when using <T>, but not <any>
combineLatest<T>(values);
Expand Down
Expand Up @@ -16,7 +16,7 @@ A.B = class {
/** @type {string[]} */
var x = [];
>x : string[]
>[] : undefined[]
>[] : string[]

/** @type {number[]} */
var y;
Expand Down
Expand Up @@ -10,20 +10,20 @@
>p : string[]

return [];
>[] : undefined[]
>[] : string[]
}

function bar(p: string[]): string[] {
>bar : (p: string[]) => string[]
>p : string[]

return [];
>[] : undefined[]
>[] : string[]
}

let a1: string[] | undefined = [];
>a1 : string[]
>[] : undefined[]
>[] : string[]

while (true) {
>true : true
Expand Down
Expand Up @@ -5,7 +5,7 @@ declare var console: any;
const arr: {y(): number}[] = [];
>arr : { y(): number; }[]
>y : () => number
>[] : undefined[]
>[] : { y(): number; }[]

for (let i = 0; i < 3; i++) {
>i : number
Expand Down
Expand Up @@ -5,7 +5,7 @@ declare var console: any;
const arr: {y(): number}[] = [];
>arr : { y(): number; }[]
>y : () => number
>[] : undefined[]
>[] : { y(): number; }[]

for (let i = 0; i < 3; i++) {
>i : number
Expand Down
Expand Up @@ -10,7 +10,7 @@ function fn() {

let arr: any[] = [];
>arr : any[]
>[] : undefined[]
>[] : any[]

switch(arr.length) {
>arr.length : number
Expand Down
Expand Up @@ -16019,6 +16019,6 @@ export function makeThing<T extends BigUnion['name']>(

children: ChildrenOf<WithName<T>>[] = [],
>children : ChildrenOf<WithName<T>>[]
>[] : undefined[]
>[] : ChildrenOf<WithName<T>>[]

) { }
Expand Up @@ -83,7 +83,7 @@ export function series<T>(tasks: Task<T>[], callback: Callback<T[]>): void {

let results: T[] = []
>results : T[]
>[] : never[]
>[] : T[]

function next() {
>next : () => void
Expand Down