Skip to content

Commit e775383

Browse files
authored
Filter out non-array types when contextually typing array literal elements (microsoft#52589)
1 parent a8ffab2 commit e775383

10 files changed

+297
-13
lines changed

src/compiler/checker.ts

+8-13
Original file line numberDiff line numberDiff line change
@@ -19574,18 +19574,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1957419574
return result;
1957519575
}
1957619576
const moreThanOneRealChildren = length(validChildren) > 1;
19577-
let arrayLikeTargetParts: Type;
19578-
let nonArrayLikeTargetParts: Type;
19579-
const iterableType = getGlobalIterableType(/*reportErrors*/ false);
19580-
if (iterableType !== emptyGenericType) {
19581-
const anyIterable = createIterableType(anyType);
19582-
arrayLikeTargetParts = filterType(childrenTargetType, t => isTypeAssignableTo(t, anyIterable));
19583-
nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isTypeAssignableTo(t, anyIterable));
19584-
}
19585-
else {
19586-
arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType);
19587-
nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t));
19588-
}
19577+
const arrayLikeTargetParts = filterType(childrenTargetType, isAssignableToAvailableAnyIterable);
19578+
const nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isAssignableToAvailableAnyIterable(t));
1958919579
if (moreThanOneRealChildren) {
1959019580
if (arrayLikeTargetParts !== neverType) {
1959119581
const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal));
@@ -23108,6 +23098,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2310823098
return isArrayLikeType(type) || isTupleLikeType(type);
2310923099
}
2311023100

23101+
function isAssignableToAvailableAnyIterable(type: Type): boolean {
23102+
const anyIterable = getGlobalIterableType(/*reportErrors*/ false) !== emptyGenericType && createIterableType(anyType);
23103+
return anyIterable ? isTypeAssignableTo(type, anyIterable) : isArrayOrTupleLikeType(type);
23104+
}
23105+
2311123106
function getTupleElementType(type: Type, index: number) {
2311223107
const propType = getTypeOfPropertyOfType(type, "" + index as __String);
2311323108
if (propType) {
@@ -29067,7 +29062,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2906729062
// type of T.
2906829063
function getContextualTypeForElementExpression(arrayContextualType: Type | undefined, index: number): Type | undefined {
2906929064
return arrayContextualType && (
29070-
index >= 0 && getTypeOfPropertyOfContextualType(arrayContextualType, "" + index as __String) ||
29065+
index >= 0 && getTypeOfPropertyOfContextualType(filterType(arrayContextualType, t => !!getIndexTypeOfType(t, numberType) || isAssignableToAvailableAnyIterable(t)), "" + index as __String) ||
2907129066
mapType(arrayContextualType, t =>
2907229067
isTupleType(t) ?
2907329068
getElementTypeOfSliceOfTupleType(t, 0, /*endSkipCount*/ 0, /*writing*/ false, /*noReductions*/ true) :
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts ===
2+
// repro from #52588
3+
4+
declare function test(
5+
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 0, 0))
6+
7+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
8+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 2, 22))
9+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
10+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 3, 23))
11+
>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, --, --))
12+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 3, 54))
13+
14+
): void;
15+
16+
test([
17+
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 0, 0))
18+
19+
(arg) => {
20+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 7, 3))
21+
22+
arg; // number
23+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts, 7, 3))
24+
25+
},
26+
]);
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs2015.ts ===
2+
// repro from #52588
3+
4+
declare function test(
5+
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void
6+
7+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
8+
>arg : Record<string, (arg: string) => void> | ((arg: number) => void)[]
9+
>arg : string
10+
>arg : number
11+
12+
): void;
13+
14+
test([
15+
>test([ (arg) => { arg; // number },]) : void
16+
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void
17+
>[ (arg) => { arg; // number },] : ((arg: number) => void)[]
18+
19+
(arg) => {
20+
>(arg) => { arg; // number } : (arg: number) => void
21+
>arg : number
22+
23+
arg; // number
24+
>arg : number
25+
26+
},
27+
]);
28+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts ===
2+
// repro from #52588
3+
4+
declare function test(
5+
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 0, 0))
6+
7+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
8+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 2, 22))
9+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
10+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 3, 23))
11+
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
12+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 3, 54))
13+
14+
): void;
15+
16+
test([
17+
>test : Symbol(test, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 0, 0))
18+
19+
(arg) => {
20+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 7, 3))
21+
22+
arg; // number
23+
>arg : Symbol(arg, Decl(contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts, 7, 3))
24+
25+
},
26+
]);
27+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
=== tests/cases/compiler/contextualSignatureInArrayElementPrefersArrayUnionMemberLibEs5.ts ===
2+
// repro from #52588
3+
4+
declare function test(
5+
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void
6+
7+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
8+
>arg : Record<string, (arg: string) => void> | ((arg: number) => void)[]
9+
>arg : string
10+
>arg : number
11+
12+
): void;
13+
14+
test([
15+
>test([ (arg) => { arg; // number },]) : void
16+
>test : (arg: Record<string, (arg: string) => void> | ((arg: number) => void)[]) => void
17+
>[ (arg) => { arg; // number },] : ((arg: number) => void)[]
18+
19+
(arg) => {
20+
>(arg) => { arg; // number } : (arg: number) => void
21+
>arg : number
22+
23+
arg; // number
24+
>arg : number
25+
26+
},
27+
]);
28+

tests/baselines/reference/contextualTypeCaching.symbols

+67
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,70 @@ emit('a', {
6060
},
6161
});
6262

63+
// simplified repro from 52589#issuecomment-1416180638
64+
declare class MyCompiler {
65+
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))
66+
67+
compile(): void;
68+
>compile : Symbol(MyCompiler.compile, Decl(contextualTypeCaching.ts, 24, 26))
69+
}
70+
interface WebpackPluginInstance {
71+
>WebpackPluginInstance : Symbol(WebpackPluginInstance, Decl(contextualTypeCaching.ts, 26, 1))
72+
73+
apply: (compiler: MyCompiler) => void;
74+
>apply : Symbol(WebpackPluginInstance.apply, Decl(contextualTypeCaching.ts, 27, 33))
75+
>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 28, 10))
76+
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))
77+
}
78+
type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void;
79+
>WebpackPluginFunction : Symbol(WebpackPluginFunction, Decl(contextualTypeCaching.ts, 29, 1))
80+
>this : Symbol(this, Decl(contextualTypeCaching.ts, 30, 30))
81+
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))
82+
>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 30, 47))
83+
>MyCompiler : Symbol(MyCompiler, Decl(contextualTypeCaching.ts, 21, 3))
84+
85+
interface Optimization {
86+
>Optimization : Symbol(Optimization, Decl(contextualTypeCaching.ts, 30, 78))
87+
88+
minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[];
89+
>minimizer : Symbol(Optimization.minimizer, Decl(contextualTypeCaching.ts, 31, 24))
90+
>WebpackPluginInstance : Symbol(WebpackPluginInstance, Decl(contextualTypeCaching.ts, 26, 1))
91+
>WebpackPluginFunction : Symbol(WebpackPluginFunction, Decl(contextualTypeCaching.ts, 29, 1))
92+
}
93+
declare const A: <T, P extends keyof T>(
94+
>A : Symbol(A, Decl(contextualTypeCaching.ts, 34, 13))
95+
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))
96+
>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20))
97+
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))
98+
99+
obj: T,
100+
>obj : Symbol(obj, Decl(contextualTypeCaching.ts, 34, 40))
101+
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))
102+
103+
prop: P,
104+
>prop : Symbol(prop, Decl(contextualTypeCaching.ts, 35, 9))
105+
>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20))
106+
107+
factory: () => T[P]
108+
>factory : Symbol(factory, Decl(contextualTypeCaching.ts, 36, 10))
109+
>T : Symbol(T, Decl(contextualTypeCaching.ts, 34, 18))
110+
>P : Symbol(P, Decl(contextualTypeCaching.ts, 34, 20))
111+
112+
) => void;
113+
export const applyOptimizationDefaults = (optimization: Optimization) => {
114+
>applyOptimizationDefaults : Symbol(applyOptimizationDefaults, Decl(contextualTypeCaching.ts, 39, 12))
115+
>optimization : Symbol(optimization, Decl(contextualTypeCaching.ts, 39, 42))
116+
>Optimization : Symbol(Optimization, Decl(contextualTypeCaching.ts, 30, 78))
117+
118+
A(optimization, "minimizer", () => [
119+
>A : Symbol(A, Decl(contextualTypeCaching.ts, 34, 13))
120+
>optimization : Symbol(optimization, Decl(contextualTypeCaching.ts, 39, 42))
121+
{
122+
apply: (compiler) => {},
123+
>apply : Symbol(apply, Decl(contextualTypeCaching.ts, 41, 5))
124+
>compiler : Symbol(compiler, Decl(contextualTypeCaching.ts, 42, 14))
125+
126+
},
127+
]);
128+
};
129+

tests/baselines/reference/contextualTypeCaching.types

+58
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,61 @@ emit('a', {
5454
},
5555
});
5656

57+
// simplified repro from 52589#issuecomment-1416180638
58+
declare class MyCompiler {
59+
>MyCompiler : MyCompiler
60+
61+
compile(): void;
62+
>compile : () => void
63+
}
64+
interface WebpackPluginInstance {
65+
apply: (compiler: MyCompiler) => void;
66+
>apply : (compiler: MyCompiler) => void
67+
>compiler : MyCompiler
68+
}
69+
type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void;
70+
>WebpackPluginFunction : (this: MyCompiler, compiler: MyCompiler) => void
71+
>this : MyCompiler
72+
>compiler : MyCompiler
73+
74+
interface Optimization {
75+
minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[];
76+
>minimizer : (WebpackPluginInstance | WebpackPluginFunction)[] | undefined
77+
}
78+
declare const A: <T, P extends keyof T>(
79+
>A : <T, P extends keyof T>(obj: T, prop: P, factory: () => T[P]) => void
80+
81+
obj: T,
82+
>obj : T
83+
84+
prop: P,
85+
>prop : P
86+
87+
factory: () => T[P]
88+
>factory : () => T[P]
89+
90+
) => void;
91+
export const applyOptimizationDefaults = (optimization: Optimization) => {
92+
>applyOptimizationDefaults : (optimization: Optimization) => void
93+
>(optimization: Optimization) => { A(optimization, "minimizer", () => [ { apply: (compiler) => {}, }, ]);} : (optimization: Optimization) => void
94+
>optimization : Optimization
95+
96+
A(optimization, "minimizer", () => [
97+
>A(optimization, "minimizer", () => [ { apply: (compiler) => {}, }, ]) : void
98+
>A : <T, P extends keyof T>(obj: T, prop: P, factory: () => T[P]) => void
99+
>optimization : Optimization
100+
>"minimizer" : "minimizer"
101+
>() => [ { apply: (compiler) => {}, }, ] : () => { apply: (compiler: MyCompiler) => void; }[]
102+
>[ { apply: (compiler) => {}, }, ] : { apply: (compiler: MyCompiler) => void; }[]
103+
{
104+
>{ apply: (compiler) => {}, } : { apply: (compiler: MyCompiler) => void; }
105+
106+
apply: (compiler) => {},
107+
>apply : (compiler: MyCompiler) => void
108+
>(compiler) => {} : (compiler: MyCompiler) => void
109+
>compiler : MyCompiler
110+
111+
},
112+
]);
113+
};
114+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
// @noEmit: true
3+
// @lib: es2015
4+
5+
// repro from #52588
6+
7+
declare function test(
8+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
9+
): void;
10+
11+
test([
12+
(arg) => {
13+
arg; // number
14+
},
15+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
// @noEmit: true
3+
// @lib: es5
4+
5+
// repro from #52588
6+
7+
declare function test(
8+
arg: Record<string, (arg: string) => void> | Array<(arg: number) => void>
9+
): void;
10+
11+
test([
12+
(arg) => {
13+
arg; // number
14+
},
15+
]);

tests/cases/compiler/contextualTypeCaching.ts

+24
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,27 @@ emit('a', {
2323
nestedCallback: (r) => {},
2424
},
2525
});
26+
27+
// simplified repro from 52589#issuecomment-1416180638
28+
declare class MyCompiler {
29+
compile(): void;
30+
}
31+
interface WebpackPluginInstance {
32+
apply: (compiler: MyCompiler) => void;
33+
}
34+
type WebpackPluginFunction = (this: MyCompiler, compiler: MyCompiler) => void;
35+
interface Optimization {
36+
minimizer?: (WebpackPluginInstance | WebpackPluginFunction)[];
37+
}
38+
declare const A: <T, P extends keyof T>(
39+
obj: T,
40+
prop: P,
41+
factory: () => T[P]
42+
) => void;
43+
export const applyOptimizationDefaults = (optimization: Optimization) => {
44+
A(optimization, "minimizer", () => [
45+
{
46+
apply: (compiler) => {},
47+
},
48+
]);
49+
};

0 commit comments

Comments
 (0)