Skip to content

Commit 09271f1

Browse files
authored
Make no inferences from binding patterns with no defaults (#35454)
* Use nonInferrableAnyType in types inferred from binding patterns * Add regression tests * Accept new baselines
1 parent b39b4e0 commit 09271f1

File tree

6 files changed

+357
-4
lines changed

6 files changed

+357
-4
lines changed

src/compiler/checker.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ namespace ts {
638638
const autoType = createIntrinsicType(TypeFlags.Any, "any");
639639
const wildcardType = createIntrinsicType(TypeFlags.Any, "any");
640640
const errorType = createIntrinsicType(TypeFlags.Any, "error");
641+
const nonInferrableAnyType = createIntrinsicType(TypeFlags.Any, "any", ObjectFlags.ContainsWideningType);
641642
const unknownType = createIntrinsicType(TypeFlags.Unknown, "unknown");
642643
const undefinedType = createIntrinsicType(TypeFlags.Undefined, "undefined");
643644
const undefinedWideningType = strictNullChecks ? undefinedType : createIntrinsicType(TypeFlags.Undefined, "undefined", ObjectFlags.ContainsWideningType);
@@ -7156,7 +7157,11 @@ namespace ts {
71567157
if (reportErrors && !declarationBelongsToPrivateAmbientMember(element)) {
71577158
reportImplicitAny(element, anyType);
71587159
}
7159-
return anyType;
7160+
// When we're including the pattern in the type (an indication we're obtaining a contextual type), we
7161+
// use the non-inferrable any type. Inference will never directly infer this type, but it is possible
7162+
// to infer a type that contains it, e.g. for a binding pattern like [foo] or { foo }. In such cases,
7163+
// widening of the binding pattern type substitutes a regular any for the non-inferrable any.
7164+
return includePatternInType ? nonInferrableAnyType : anyType;
71607165
}
71617166

71627167
// Return the type implied by an object binding pattern
@@ -7188,6 +7193,7 @@ namespace ts {
71887193
result.objectFlags |= objectFlags;
71897194
if (includePatternInType) {
71907195
result.pattern = pattern;
7196+
result.objectFlags |= ObjectFlags.ContainsObjectOrArrayLiteral;
71917197
}
71927198
return result;
71937199
}
@@ -7206,6 +7212,7 @@ namespace ts {
72067212
if (includePatternInType) {
72077213
result = cloneTypeReference(result);
72087214
result.pattern = pattern;
7215+
result.objectFlags |= ObjectFlags.ContainsObjectOrArrayLiteral;
72097216
}
72107217
return result;
72117218
}
@@ -17025,7 +17032,7 @@ namespace ts {
1702517032
return type.widened;
1702617033
}
1702717034
let result: Type | undefined;
17028-
if (type.flags & TypeFlags.Nullable) {
17035+
if (type.flags & (TypeFlags.Any | TypeFlags.Nullable)) {
1702917036
result = anyType;
1703017037
}
1703117038
else if (isObjectLiteralType(type)) {
@@ -17535,7 +17542,8 @@ namespace ts {
1753517542
// not contain anyFunctionType when we come back to this argument for its second round
1753617543
// of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard
1753717544
// when constructing types from type parameters that had no inference candidates).
17538-
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === silentNeverType || (priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType))) {
17545+
if (getObjectFlags(source) & ObjectFlags.NonInferrableType || source === nonInferrableAnyType || source === silentNeverType ||
17546+
(priority & InferencePriority.ReturnType && (source === autoType || source === autoArrayType))) {
1753917547
return;
1754017548
}
1754117549
const inference = getInferenceInfoForType(target);

src/compiler/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4232,7 +4232,7 @@ namespace ts {
42324232
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
42334233
StructuredOrInstantiable = StructuredType | Instantiable,
42344234
/* @internal */
4235-
ObjectFlagsType = Nullable | Never | Object | Union | Intersection,
4235+
ObjectFlagsType = Any | Nullable | Never | Object | Union | Intersection,
42364236
/* @internal */
42374237
Simplifiable = IndexedAccess | Conditional,
42384238
// 'Narrowable' types are types where narrowing actually narrows.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
//// [inferFromBindingPattern.ts]
2+
declare function f1<T extends string>(): T;
3+
declare function f2<T extends string>(): [T];
4+
declare function f3<T extends string>(): { x: T };
5+
6+
let x1 = f1(); // string
7+
let [x2] = f2(); // string
8+
let { x: x3 } = f3(); // string
9+
10+
// Repro from #30379
11+
12+
function foo<T = number>(): [T] {
13+
return [42 as any]
14+
}
15+
const [x] = foo(); // [number]
16+
17+
// Repro from #35291
18+
19+
interface SelectProps<T, K> {
20+
selector?: (obj: T) => K;
21+
}
22+
23+
type SelectResult<T, K> = [K, T];
24+
25+
interface Person {
26+
name: string;
27+
surname: string;
28+
}
29+
30+
declare function selectJohn<K = Person>(props?: SelectProps<Person, K>): SelectResult<Person, K>;
31+
32+
const [person] = selectJohn();
33+
const [any, whatever] = selectJohn();
34+
const john = selectJohn();
35+
const [personAgain, nufinspecial] = john;
36+
37+
// Repro from #35291
38+
39+
declare function makeTuple<T1>(arg: T1): [T1];
40+
declare function stringy<T = string>(arg?: T): T;
41+
42+
const isStringTuple = makeTuple(stringy()); // [string]
43+
const [isAny] = makeTuple(stringy()); // [string]
44+
45+
46+
//// [inferFromBindingPattern.js]
47+
"use strict";
48+
var x1 = f1(); // string
49+
var x2 = f2()[0]; // string
50+
var x3 = f3().x; // string
51+
// Repro from #30379
52+
function foo() {
53+
return [42];
54+
}
55+
var x = foo()[0]; // [number]
56+
var person = selectJohn()[0];
57+
var _a = selectJohn(), any = _a[0], whatever = _a[1];
58+
var john = selectJohn();
59+
var personAgain = john[0], nufinspecial = john[1];
60+
var isStringTuple = makeTuple(stringy()); // [string]
61+
var isAny = makeTuple(stringy())[0]; // [string]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
=== tests/cases/conformance/inferFromBindingPattern.ts ===
2+
declare function f1<T extends string>(): T;
3+
>f1 : Symbol(f1, Decl(inferFromBindingPattern.ts, 0, 0))
4+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 0, 20))
5+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 0, 20))
6+
7+
declare function f2<T extends string>(): [T];
8+
>f2 : Symbol(f2, Decl(inferFromBindingPattern.ts, 0, 43))
9+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 1, 20))
10+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 1, 20))
11+
12+
declare function f3<T extends string>(): { x: T };
13+
>f3 : Symbol(f3, Decl(inferFromBindingPattern.ts, 1, 45))
14+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 2, 20))
15+
>x : Symbol(x, Decl(inferFromBindingPattern.ts, 2, 42))
16+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 2, 20))
17+
18+
let x1 = f1(); // string
19+
>x1 : Symbol(x1, Decl(inferFromBindingPattern.ts, 4, 3))
20+
>f1 : Symbol(f1, Decl(inferFromBindingPattern.ts, 0, 0))
21+
22+
let [x2] = f2(); // string
23+
>x2 : Symbol(x2, Decl(inferFromBindingPattern.ts, 5, 5))
24+
>f2 : Symbol(f2, Decl(inferFromBindingPattern.ts, 0, 43))
25+
26+
let { x: x3 } = f3(); // string
27+
>x : Symbol(x, Decl(inferFromBindingPattern.ts, 2, 42))
28+
>x3 : Symbol(x3, Decl(inferFromBindingPattern.ts, 6, 5))
29+
>f3 : Symbol(f3, Decl(inferFromBindingPattern.ts, 1, 45))
30+
31+
// Repro from #30379
32+
33+
function foo<T = number>(): [T] {
34+
>foo : Symbol(foo, Decl(inferFromBindingPattern.ts, 6, 21))
35+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 10, 13))
36+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 10, 13))
37+
38+
return [42 as any]
39+
}
40+
const [x] = foo(); // [number]
41+
>x : Symbol(x, Decl(inferFromBindingPattern.ts, 13, 7))
42+
>foo : Symbol(foo, Decl(inferFromBindingPattern.ts, 6, 21))
43+
44+
// Repro from #35291
45+
46+
interface SelectProps<T, K> {
47+
>SelectProps : Symbol(SelectProps, Decl(inferFromBindingPattern.ts, 13, 18))
48+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 17, 22))
49+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 17, 24))
50+
51+
selector?: (obj: T) => K;
52+
>selector : Symbol(SelectProps.selector, Decl(inferFromBindingPattern.ts, 17, 29))
53+
>obj : Symbol(obj, Decl(inferFromBindingPattern.ts, 18, 14))
54+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 17, 22))
55+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 17, 24))
56+
}
57+
58+
type SelectResult<T, K> = [K, T];
59+
>SelectResult : Symbol(SelectResult, Decl(inferFromBindingPattern.ts, 19, 1))
60+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 21, 18))
61+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 21, 20))
62+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 21, 20))
63+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 21, 18))
64+
65+
interface Person {
66+
>Person : Symbol(Person, Decl(inferFromBindingPattern.ts, 21, 33))
67+
68+
name: string;
69+
>name : Symbol(Person.name, Decl(inferFromBindingPattern.ts, 23, 18))
70+
71+
surname: string;
72+
>surname : Symbol(Person.surname, Decl(inferFromBindingPattern.ts, 24, 15))
73+
}
74+
75+
declare function selectJohn<K = Person>(props?: SelectProps<Person, K>): SelectResult<Person, K>;
76+
>selectJohn : Symbol(selectJohn, Decl(inferFromBindingPattern.ts, 26, 1))
77+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 28, 28))
78+
>Person : Symbol(Person, Decl(inferFromBindingPattern.ts, 21, 33))
79+
>props : Symbol(props, Decl(inferFromBindingPattern.ts, 28, 40))
80+
>SelectProps : Symbol(SelectProps, Decl(inferFromBindingPattern.ts, 13, 18))
81+
>Person : Symbol(Person, Decl(inferFromBindingPattern.ts, 21, 33))
82+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 28, 28))
83+
>SelectResult : Symbol(SelectResult, Decl(inferFromBindingPattern.ts, 19, 1))
84+
>Person : Symbol(Person, Decl(inferFromBindingPattern.ts, 21, 33))
85+
>K : Symbol(K, Decl(inferFromBindingPattern.ts, 28, 28))
86+
87+
const [person] = selectJohn();
88+
>person : Symbol(person, Decl(inferFromBindingPattern.ts, 30, 7))
89+
>selectJohn : Symbol(selectJohn, Decl(inferFromBindingPattern.ts, 26, 1))
90+
91+
const [any, whatever] = selectJohn();
92+
>any : Symbol(any, Decl(inferFromBindingPattern.ts, 31, 7))
93+
>whatever : Symbol(whatever, Decl(inferFromBindingPattern.ts, 31, 11))
94+
>selectJohn : Symbol(selectJohn, Decl(inferFromBindingPattern.ts, 26, 1))
95+
96+
const john = selectJohn();
97+
>john : Symbol(john, Decl(inferFromBindingPattern.ts, 32, 5))
98+
>selectJohn : Symbol(selectJohn, Decl(inferFromBindingPattern.ts, 26, 1))
99+
100+
const [personAgain, nufinspecial] = john;
101+
>personAgain : Symbol(personAgain, Decl(inferFromBindingPattern.ts, 33, 7))
102+
>nufinspecial : Symbol(nufinspecial, Decl(inferFromBindingPattern.ts, 33, 19))
103+
>john : Symbol(john, Decl(inferFromBindingPattern.ts, 32, 5))
104+
105+
// Repro from #35291
106+
107+
declare function makeTuple<T1>(arg: T1): [T1];
108+
>makeTuple : Symbol(makeTuple, Decl(inferFromBindingPattern.ts, 33, 41))
109+
>T1 : Symbol(T1, Decl(inferFromBindingPattern.ts, 37, 27))
110+
>arg : Symbol(arg, Decl(inferFromBindingPattern.ts, 37, 31))
111+
>T1 : Symbol(T1, Decl(inferFromBindingPattern.ts, 37, 27))
112+
>T1 : Symbol(T1, Decl(inferFromBindingPattern.ts, 37, 27))
113+
114+
declare function stringy<T = string>(arg?: T): T;
115+
>stringy : Symbol(stringy, Decl(inferFromBindingPattern.ts, 37, 46))
116+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 38, 25))
117+
>arg : Symbol(arg, Decl(inferFromBindingPattern.ts, 38, 37))
118+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 38, 25))
119+
>T : Symbol(T, Decl(inferFromBindingPattern.ts, 38, 25))
120+
121+
const isStringTuple = makeTuple(stringy()); // [string]
122+
>isStringTuple : Symbol(isStringTuple, Decl(inferFromBindingPattern.ts, 40, 5))
123+
>makeTuple : Symbol(makeTuple, Decl(inferFromBindingPattern.ts, 33, 41))
124+
>stringy : Symbol(stringy, Decl(inferFromBindingPattern.ts, 37, 46))
125+
126+
const [isAny] = makeTuple(stringy()); // [string]
127+
>isAny : Symbol(isAny, Decl(inferFromBindingPattern.ts, 41, 7))
128+
>makeTuple : Symbol(makeTuple, Decl(inferFromBindingPattern.ts, 33, 41))
129+
>stringy : Symbol(stringy, Decl(inferFromBindingPattern.ts, 37, 46))
130+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
=== tests/cases/conformance/inferFromBindingPattern.ts ===
2+
declare function f1<T extends string>(): T;
3+
>f1 : <T extends string>() => T
4+
5+
declare function f2<T extends string>(): [T];
6+
>f2 : <T extends string>() => [T]
7+
8+
declare function f3<T extends string>(): { x: T };
9+
>f3 : <T extends string>() => { x: T; }
10+
>x : T
11+
12+
let x1 = f1(); // string
13+
>x1 : string
14+
>f1() : string
15+
>f1 : <T extends string>() => T
16+
17+
let [x2] = f2(); // string
18+
>x2 : string
19+
>f2() : [string]
20+
>f2 : <T extends string>() => [T]
21+
22+
let { x: x3 } = f3(); // string
23+
>x : any
24+
>x3 : string
25+
>f3() : { x: string; }
26+
>f3 : <T extends string>() => { x: T; }
27+
28+
// Repro from #30379
29+
30+
function foo<T = number>(): [T] {
31+
>foo : <T = number>() => [T]
32+
33+
return [42 as any]
34+
>[42 as any] : [any]
35+
>42 as any : any
36+
>42 : 42
37+
}
38+
const [x] = foo(); // [number]
39+
>x : number
40+
>foo() : [number]
41+
>foo : <T = number>() => [T]
42+
43+
// Repro from #35291
44+
45+
interface SelectProps<T, K> {
46+
selector?: (obj: T) => K;
47+
>selector : ((obj: T) => K) | undefined
48+
>obj : T
49+
}
50+
51+
type SelectResult<T, K> = [K, T];
52+
>SelectResult : SelectResult<T, K>
53+
54+
interface Person {
55+
name: string;
56+
>name : string
57+
58+
surname: string;
59+
>surname : string
60+
}
61+
62+
declare function selectJohn<K = Person>(props?: SelectProps<Person, K>): SelectResult<Person, K>;
63+
>selectJohn : <K = Person>(props?: SelectProps<Person, K> | undefined) => SelectResult<Person, K>
64+
>props : SelectProps<Person, K> | undefined
65+
66+
const [person] = selectJohn();
67+
>person : Person
68+
>selectJohn() : SelectResult<Person, Person>
69+
>selectJohn : <K = Person>(props?: SelectProps<Person, K> | undefined) => SelectResult<Person, K>
70+
71+
const [any, whatever] = selectJohn();
72+
>any : Person
73+
>whatever : Person
74+
>selectJohn() : SelectResult<Person, Person>
75+
>selectJohn : <K = Person>(props?: SelectProps<Person, K> | undefined) => SelectResult<Person, K>
76+
77+
const john = selectJohn();
78+
>john : SelectResult<Person, Person>
79+
>selectJohn() : SelectResult<Person, Person>
80+
>selectJohn : <K = Person>(props?: SelectProps<Person, K> | undefined) => SelectResult<Person, K>
81+
82+
const [personAgain, nufinspecial] = john;
83+
>personAgain : Person
84+
>nufinspecial : Person
85+
>john : SelectResult<Person, Person>
86+
87+
// Repro from #35291
88+
89+
declare function makeTuple<T1>(arg: T1): [T1];
90+
>makeTuple : <T1>(arg: T1) => [T1]
91+
>arg : T1
92+
93+
declare function stringy<T = string>(arg?: T): T;
94+
>stringy : <T = string>(arg?: T | undefined) => T
95+
>arg : T | undefined
96+
97+
const isStringTuple = makeTuple(stringy()); // [string]
98+
>isStringTuple : [string]
99+
>makeTuple(stringy()) : [string]
100+
>makeTuple : <T1>(arg: T1) => [T1]
101+
>stringy() : string
102+
>stringy : <T = string>(arg?: T | undefined) => T
103+
104+
const [isAny] = makeTuple(stringy()); // [string]
105+
>isAny : string
106+
>makeTuple(stringy()) : [string]
107+
>makeTuple : <T1>(arg: T1) => [T1]
108+
>stringy() : string
109+
>stringy : <T = string>(arg?: T | undefined) => T
110+

0 commit comments

Comments
 (0)