Skip to content

Commit 2acf3a3

Browse files
TypeScript Botjakebailey
TypeScript Bot
andauthored
Cherry-pick PR #50691 into release-4.8 (#50743)
Component commits: 3644959 Add test case 17f6e57 Revert removal of nonInferrableAnyType cafebee Rename test Co-authored-by: Jake Bailey <[email protected]>
1 parent 39576e6 commit 2acf3a3

5 files changed

+234
-2
lines changed

Diff for: src/compiler/checker.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,7 @@ namespace ts {
789789
const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
790790
const errorType = createIntrinsicType(TypeFlags.Any, "error");
791791
const unresolvedType = createIntrinsicType(TypeFlags.Any, "unresolved");
792+
const nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType);
792793
const intrinsicMarkerType = createIntrinsicType(TypeFlags.Any, "intrinsic");
793794
const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
794795
const nonNullUnknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
@@ -9540,7 +9541,11 @@ namespace ts {
95409541
if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) {
95419542
reportImplicitAny(element, anyType);
95429543
}
9543-
return anyType;
9544+
// When we're including the pattern in the type (an indication we're obtaining a contextual type), we
9545+
// use a non-inferrable any type. Inference will never directly infer this type, but it is possible
9546+
// to infer a type that contains it, e.g. for a binding pattern like [foo] or { foo }. In such cases,
9547+
// widening of the binding pattern type substitutes a regular any for the non-inferrable any.
9548+
return includePatternInType ? nonInferrableAnyType : anyType;
95449549
}
95459550

95469551
// Return the type implied by an object binding pattern
@@ -22598,7 +22603,10 @@ namespace ts {
2259822603
//
2259922604
// This flag is infectious; if we produce Box<never> (where never is silentNeverType), Box<never> is
2260022605
// also non-inferrable.
22601-
if (getObjectFlags(source) & ObjectFlags.NonInferrableType) {
22606+
//
22607+
// As a special case, also ignore nonInferrableAnyType, which is a special form of the any type
22608+
// used as a stand-in for binding elements when they are being inferred.
22609+
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType) {
2260222610
return;
2260322611
}
2260422612
if (!inference.isFixed) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//// [inferStringLiteralUnionForBindingElement.ts]
2+
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };
3+
4+
function func1() {
5+
const { firstKey } = func({keys: ["aa", "bb"]})
6+
const a: "aa" | "bb" = firstKey;
7+
8+
const { keys } = func({keys: ["aa", "bb"]})
9+
const b: ("aa" | "bb")[] = keys;
10+
}
11+
12+
function func2() {
13+
const { keys, firstKey } = func({keys: ["aa", "bb"]})
14+
const a: "aa" | "bb" = firstKey;
15+
const b: ("aa" | "bb")[] = keys;
16+
}
17+
18+
function func3() {
19+
const x = func({keys: ["aa", "bb"]})
20+
const a: "aa" | "bb" = x.firstKey;
21+
const b: ("aa" | "bb")[] = x.keys;
22+
}
23+
24+
25+
//// [inferStringLiteralUnionForBindingElement.js]
26+
function func1() {
27+
var firstKey = func({ keys: ["aa", "bb"] }).firstKey;
28+
var a = firstKey;
29+
var keys = func({ keys: ["aa", "bb"] }).keys;
30+
var b = keys;
31+
}
32+
function func2() {
33+
var _a = func({ keys: ["aa", "bb"] }), keys = _a.keys, firstKey = _a.firstKey;
34+
var a = firstKey;
35+
var b = keys;
36+
}
37+
function func3() {
38+
var x = func({ keys: ["aa", "bb"] });
39+
var a = x.firstKey;
40+
var b = x.keys;
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
=== tests/cases/compiler/inferStringLiteralUnionForBindingElement.ts ===
2+
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };
3+
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
4+
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
5+
>arg : Symbol(arg, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 40))
6+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 46))
7+
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
8+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 62))
9+
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
10+
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 82))
11+
>T : Symbol(T, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 22))
12+
13+
function func1() {
14+
>func1 : Symbol(func1, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 107))
15+
16+
const { firstKey } = func({keys: ["aa", "bb"]})
17+
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 3, 11))
18+
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
19+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 3, 31))
20+
21+
const a: "aa" | "bb" = firstKey;
22+
>a : Symbol(a, Decl(inferStringLiteralUnionForBindingElement.ts, 4, 9))
23+
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 3, 11))
24+
25+
const { keys } = func({keys: ["aa", "bb"]})
26+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 6, 11))
27+
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
28+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 6, 27))
29+
30+
const b: ("aa" | "bb")[] = keys;
31+
>b : Symbol(b, Decl(inferStringLiteralUnionForBindingElement.ts, 7, 9))
32+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 6, 11))
33+
}
34+
35+
function func2() {
36+
>func2 : Symbol(func2, Decl(inferStringLiteralUnionForBindingElement.ts, 8, 1))
37+
38+
const { keys, firstKey } = func({keys: ["aa", "bb"]})
39+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 11))
40+
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 17))
41+
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
42+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 37))
43+
44+
const a: "aa" | "bb" = firstKey;
45+
>a : Symbol(a, Decl(inferStringLiteralUnionForBindingElement.ts, 12, 9))
46+
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 17))
47+
48+
const b: ("aa" | "bb")[] = keys;
49+
>b : Symbol(b, Decl(inferStringLiteralUnionForBindingElement.ts, 13, 9))
50+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 11, 11))
51+
}
52+
53+
function func3() {
54+
>func3 : Symbol(func3, Decl(inferStringLiteralUnionForBindingElement.ts, 14, 1))
55+
56+
const x = func({keys: ["aa", "bb"]})
57+
>x : Symbol(x, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 9))
58+
>func : Symbol(func, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 0))
59+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 20))
60+
61+
const a: "aa" | "bb" = x.firstKey;
62+
>a : Symbol(a, Decl(inferStringLiteralUnionForBindingElement.ts, 18, 9))
63+
>x.firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 82))
64+
>x : Symbol(x, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 9))
65+
>firstKey : Symbol(firstKey, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 82))
66+
67+
const b: ("aa" | "bb")[] = x.keys;
68+
>b : Symbol(b, Decl(inferStringLiteralUnionForBindingElement.ts, 19, 9))
69+
>x.keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 62))
70+
>x : Symbol(x, Decl(inferStringLiteralUnionForBindingElement.ts, 17, 9))
71+
>keys : Symbol(keys, Decl(inferStringLiteralUnionForBindingElement.ts, 0, 62))
72+
}
73+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
=== tests/cases/compiler/inferStringLiteralUnionForBindingElement.ts ===
2+
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };
3+
>func : <T extends string>(arg: { keys: T[];}) => { readonly keys: T[]; readonly firstKey: T;}
4+
>arg : { keys: T[]; }
5+
>keys : T[]
6+
>keys : T[]
7+
>firstKey : T
8+
9+
function func1() {
10+
>func1 : () => void
11+
12+
const { firstKey } = func({keys: ["aa", "bb"]})
13+
>firstKey : "aa" | "bb"
14+
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
15+
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
16+
>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; }
17+
>keys : ("aa" | "bb")[]
18+
>["aa", "bb"] : ("aa" | "bb")[]
19+
>"aa" : "aa"
20+
>"bb" : "bb"
21+
22+
const a: "aa" | "bb" = firstKey;
23+
>a : "aa" | "bb"
24+
>firstKey : "aa" | "bb"
25+
26+
const { keys } = func({keys: ["aa", "bb"]})
27+
>keys : ("aa" | "bb")[]
28+
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
29+
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
30+
>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; }
31+
>keys : ("aa" | "bb")[]
32+
>["aa", "bb"] : ("aa" | "bb")[]
33+
>"aa" : "aa"
34+
>"bb" : "bb"
35+
36+
const b: ("aa" | "bb")[] = keys;
37+
>b : ("aa" | "bb")[]
38+
>keys : ("aa" | "bb")[]
39+
}
40+
41+
function func2() {
42+
>func2 : () => void
43+
44+
const { keys, firstKey } = func({keys: ["aa", "bb"]})
45+
>keys : ("aa" | "bb")[]
46+
>firstKey : "aa" | "bb"
47+
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
48+
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
49+
>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; }
50+
>keys : ("aa" | "bb")[]
51+
>["aa", "bb"] : ("aa" | "bb")[]
52+
>"aa" : "aa"
53+
>"bb" : "bb"
54+
55+
const a: "aa" | "bb" = firstKey;
56+
>a : "aa" | "bb"
57+
>firstKey : "aa" | "bb"
58+
59+
const b: ("aa" | "bb")[] = keys;
60+
>b : ("aa" | "bb")[]
61+
>keys : ("aa" | "bb")[]
62+
}
63+
64+
function func3() {
65+
>func3 : () => void
66+
67+
const x = func({keys: ["aa", "bb"]})
68+
>x : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
69+
>func({keys: ["aa", "bb"]}) : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
70+
>func : <T extends string>(arg: { keys: T[]; }) => { readonly keys: T[]; readonly firstKey: T; }
71+
>{keys: ["aa", "bb"]} : { keys: ("aa" | "bb")[]; }
72+
>keys : ("aa" | "bb")[]
73+
>["aa", "bb"] : ("aa" | "bb")[]
74+
>"aa" : "aa"
75+
>"bb" : "bb"
76+
77+
const a: "aa" | "bb" = x.firstKey;
78+
>a : "aa" | "bb"
79+
>x.firstKey : "aa" | "bb"
80+
>x : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
81+
>firstKey : "aa" | "bb"
82+
83+
const b: ("aa" | "bb")[] = x.keys;
84+
>b : ("aa" | "bb")[]
85+
>x.keys : ("aa" | "bb")[]
86+
>x : { readonly keys: ("aa" | "bb")[]; readonly firstKey: "aa" | "bb"; }
87+
>keys : ("aa" | "bb")[]
88+
}
89+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
declare function func<T extends string>(arg: { keys: T[] }): { readonly keys: T[]; readonly firstKey: T; };
2+
3+
function func1() {
4+
const { firstKey } = func({keys: ["aa", "bb"]})
5+
const a: "aa" | "bb" = firstKey;
6+
7+
const { keys } = func({keys: ["aa", "bb"]})
8+
const b: ("aa" | "bb")[] = keys;
9+
}
10+
11+
function func2() {
12+
const { keys, firstKey } = func({keys: ["aa", "bb"]})
13+
const a: "aa" | "bb" = firstKey;
14+
const b: ("aa" | "bb")[] = keys;
15+
}
16+
17+
function func3() {
18+
const x = func({keys: ["aa", "bb"]})
19+
const a: "aa" | "bb" = x.firstKey;
20+
const b: ("aa" | "bb")[] = x.keys;
21+
}

0 commit comments

Comments
 (0)