Skip to content

Commit a55c0b7

Browse files
authored
Allow drawing inferences to conditional type branches (#27012)
* Allow drawing inferences to conditional type branches * Fix lint
1 parent c3b4f72 commit a55c0b7

6 files changed

+287
-1
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13508,6 +13508,9 @@ namespace ts {
1350813508
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
1350913509
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
1351013510
}
13511+
else if (target.flags & TypeFlags.Conditional) {
13512+
inferFromTypes(source, getUnionType([getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)]));
13513+
}
1351113514
else if (target.flags & TypeFlags.UnionOrIntersection) {
1351213515
const targetTypes = (<UnionOrIntersectionType>target).types;
1351313516
let typeVariableCount = 0;
@@ -13754,7 +13757,7 @@ namespace ts {
1375413757

1375513758
function hasPrimitiveConstraint(type: TypeParameter): boolean {
1375613759
const constraint = getConstraintOfTypeParameter(type);
13757-
return !!constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
13760+
return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index);
1375813761
}
1375913762

1376013763
function isObjectLiteralType(type: Type) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
tests/cases/compiler/extractInferenceImprovement.ts(26,26): error TS2345: Argument of type 'unique symbol' is not assignable to parameter of type 'never'.
2+
tests/cases/compiler/extractInferenceImprovement.ts(28,26): error TS2345: Argument of type 'unique symbol' is not assignable to parameter of type '"first" | "second"'.
3+
4+
5+
==== tests/cases/compiler/extractInferenceImprovement.ts (2 errors) ====
6+
// repro mostly from https://github.com/Microsoft/TypeScript/issues/25065
7+
function getProperty2<T, K extends keyof T>(obj: T, key: Extract<K, string>): T[K] {
8+
return obj[key];
9+
}
10+
11+
function getProperty3<T, K extends Extract<keyof T, string>>(obj: T, key: K): T[K] {
12+
return obj[key];
13+
}
14+
15+
const s = Symbol();
16+
interface StrNum {
17+
first: string;
18+
second: number;
19+
[s]: string;
20+
}
21+
const obj: StrNum = {} as any;
22+
23+
let prop: string;
24+
25+
// should work
26+
prop = getProperty2(obj, 'first');
27+
28+
prop = getProperty3(obj, 'first');
29+
30+
// Should fail
31+
prop = getProperty2(obj, s);
32+
~
33+
!!! error TS2345: Argument of type 'unique symbol' is not assignable to parameter of type 'never'.
34+
35+
prop = getProperty3(obj, s);
36+
~
37+
!!! error TS2345: Argument of type 'unique symbol' is not assignable to parameter of type '"first" | "second"'.
38+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//// [extractInferenceImprovement.ts]
2+
// repro mostly from https://github.com/Microsoft/TypeScript/issues/25065
3+
function getProperty2<T, K extends keyof T>(obj: T, key: Extract<K, string>): T[K] {
4+
return obj[key];
5+
}
6+
7+
function getProperty3<T, K extends Extract<keyof T, string>>(obj: T, key: K): T[K] {
8+
return obj[key];
9+
}
10+
11+
const s = Symbol();
12+
interface StrNum {
13+
first: string;
14+
second: number;
15+
[s]: string;
16+
}
17+
const obj: StrNum = {} as any;
18+
19+
let prop: string;
20+
21+
// should work
22+
prop = getProperty2(obj, 'first');
23+
24+
prop = getProperty3(obj, 'first');
25+
26+
// Should fail
27+
prop = getProperty2(obj, s);
28+
29+
prop = getProperty3(obj, s);
30+
31+
32+
//// [extractInferenceImprovement.js]
33+
// repro mostly from https://github.com/Microsoft/TypeScript/issues/25065
34+
function getProperty2(obj, key) {
35+
return obj[key];
36+
}
37+
function getProperty3(obj, key) {
38+
return obj[key];
39+
}
40+
const s = Symbol();
41+
const obj = {};
42+
let prop;
43+
// should work
44+
prop = getProperty2(obj, 'first');
45+
prop = getProperty3(obj, 'first');
46+
// Should fail
47+
prop = getProperty2(obj, s);
48+
prop = getProperty3(obj, s);
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
=== tests/cases/compiler/extractInferenceImprovement.ts ===
2+
// repro mostly from https://github.com/Microsoft/TypeScript/issues/25065
3+
function getProperty2<T, K extends keyof T>(obj: T, key: Extract<K, string>): T[K] {
4+
>getProperty2 : Symbol(getProperty2, Decl(extractInferenceImprovement.ts, 0, 0))
5+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 1, 22))
6+
>K : Symbol(K, Decl(extractInferenceImprovement.ts, 1, 24))
7+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 1, 22))
8+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 1, 44))
9+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 1, 22))
10+
>key : Symbol(key, Decl(extractInferenceImprovement.ts, 1, 51))
11+
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
12+
>K : Symbol(K, Decl(extractInferenceImprovement.ts, 1, 24))
13+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 1, 22))
14+
>K : Symbol(K, Decl(extractInferenceImprovement.ts, 1, 24))
15+
16+
return obj[key];
17+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 1, 44))
18+
>key : Symbol(key, Decl(extractInferenceImprovement.ts, 1, 51))
19+
}
20+
21+
function getProperty3<T, K extends Extract<keyof T, string>>(obj: T, key: K): T[K] {
22+
>getProperty3 : Symbol(getProperty3, Decl(extractInferenceImprovement.ts, 3, 1))
23+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 5, 22))
24+
>K : Symbol(K, Decl(extractInferenceImprovement.ts, 5, 24))
25+
>Extract : Symbol(Extract, Decl(lib.es5.d.ts, --, --))
26+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 5, 22))
27+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 5, 61))
28+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 5, 22))
29+
>key : Symbol(key, Decl(extractInferenceImprovement.ts, 5, 68))
30+
>K : Symbol(K, Decl(extractInferenceImprovement.ts, 5, 24))
31+
>T : Symbol(T, Decl(extractInferenceImprovement.ts, 5, 22))
32+
>K : Symbol(K, Decl(extractInferenceImprovement.ts, 5, 24))
33+
34+
return obj[key];
35+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 5, 61))
36+
>key : Symbol(key, Decl(extractInferenceImprovement.ts, 5, 68))
37+
}
38+
39+
const s = Symbol();
40+
>s : Symbol(s, Decl(extractInferenceImprovement.ts, 9, 5))
41+
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --))
42+
43+
interface StrNum {
44+
>StrNum : Symbol(StrNum, Decl(extractInferenceImprovement.ts, 9, 19))
45+
46+
first: string;
47+
>first : Symbol(StrNum.first, Decl(extractInferenceImprovement.ts, 10, 18))
48+
49+
second: number;
50+
>second : Symbol(StrNum.second, Decl(extractInferenceImprovement.ts, 11, 18))
51+
52+
[s]: string;
53+
>[s] : Symbol(StrNum[s], Decl(extractInferenceImprovement.ts, 12, 19))
54+
>s : Symbol(s, Decl(extractInferenceImprovement.ts, 9, 5))
55+
}
56+
const obj: StrNum = {} as any;
57+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 15, 5))
58+
>StrNum : Symbol(StrNum, Decl(extractInferenceImprovement.ts, 9, 19))
59+
60+
let prop: string;
61+
>prop : Symbol(prop, Decl(extractInferenceImprovement.ts, 17, 3))
62+
63+
// should work
64+
prop = getProperty2(obj, 'first');
65+
>prop : Symbol(prop, Decl(extractInferenceImprovement.ts, 17, 3))
66+
>getProperty2 : Symbol(getProperty2, Decl(extractInferenceImprovement.ts, 0, 0))
67+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 15, 5))
68+
69+
prop = getProperty3(obj, 'first');
70+
>prop : Symbol(prop, Decl(extractInferenceImprovement.ts, 17, 3))
71+
>getProperty3 : Symbol(getProperty3, Decl(extractInferenceImprovement.ts, 3, 1))
72+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 15, 5))
73+
74+
// Should fail
75+
prop = getProperty2(obj, s);
76+
>prop : Symbol(prop, Decl(extractInferenceImprovement.ts, 17, 3))
77+
>getProperty2 : Symbol(getProperty2, Decl(extractInferenceImprovement.ts, 0, 0))
78+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 15, 5))
79+
>s : Symbol(s, Decl(extractInferenceImprovement.ts, 9, 5))
80+
81+
prop = getProperty3(obj, s);
82+
>prop : Symbol(prop, Decl(extractInferenceImprovement.ts, 17, 3))
83+
>getProperty3 : Symbol(getProperty3, Decl(extractInferenceImprovement.ts, 3, 1))
84+
>obj : Symbol(obj, Decl(extractInferenceImprovement.ts, 15, 5))
85+
>s : Symbol(s, Decl(extractInferenceImprovement.ts, 9, 5))
86+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
=== tests/cases/compiler/extractInferenceImprovement.ts ===
2+
// repro mostly from https://github.com/Microsoft/TypeScript/issues/25065
3+
function getProperty2<T, K extends keyof T>(obj: T, key: Extract<K, string>): T[K] {
4+
>getProperty2 : <T, K extends keyof T>(obj: T, key: Extract<K, string>) => T[K]
5+
>obj : T
6+
>key : Extract<K, string>
7+
8+
return obj[key];
9+
>obj[key] : T[Extract<K, string>]
10+
>obj : T
11+
>key : Extract<K, string>
12+
}
13+
14+
function getProperty3<T, K extends Extract<keyof T, string>>(obj: T, key: K): T[K] {
15+
>getProperty3 : <T, K extends Extract<keyof T, string>>(obj: T, key: K) => T[K]
16+
>obj : T
17+
>key : K
18+
19+
return obj[key];
20+
>obj[key] : T[K]
21+
>obj : T
22+
>key : K
23+
}
24+
25+
const s = Symbol();
26+
>s : unique symbol
27+
>Symbol() : unique symbol
28+
>Symbol : SymbolConstructor
29+
30+
interface StrNum {
31+
first: string;
32+
>first : string
33+
34+
second: number;
35+
>second : number
36+
37+
[s]: string;
38+
>[s] : string
39+
>s : unique symbol
40+
}
41+
const obj: StrNum = {} as any;
42+
>obj : StrNum
43+
>{} as any : any
44+
>{} : {}
45+
46+
let prop: string;
47+
>prop : string
48+
49+
// should work
50+
prop = getProperty2(obj, 'first');
51+
>prop = getProperty2(obj, 'first') : string
52+
>prop : string
53+
>getProperty2(obj, 'first') : string
54+
>getProperty2 : <T, K extends keyof T>(obj: T, key: Extract<K, string>) => T[K]
55+
>obj : StrNum
56+
>'first' : "first"
57+
58+
prop = getProperty3(obj, 'first');
59+
>prop = getProperty3(obj, 'first') : string
60+
>prop : string
61+
>getProperty3(obj, 'first') : string
62+
>getProperty3 : <T, K extends Extract<keyof T, string>>(obj: T, key: K) => T[K]
63+
>obj : StrNum
64+
>'first' : "first"
65+
66+
// Should fail
67+
prop = getProperty2(obj, s);
68+
>prop = getProperty2(obj, s) : any
69+
>prop : string
70+
>getProperty2(obj, s) : any
71+
>getProperty2 : <T, K extends keyof T>(obj: T, key: Extract<K, string>) => T[K]
72+
>obj : StrNum
73+
>s : unique symbol
74+
75+
prop = getProperty3(obj, s);
76+
>prop = getProperty3(obj, s) : any
77+
>prop : string
78+
>getProperty3(obj, s) : any
79+
>getProperty3 : <T, K extends Extract<keyof T, string>>(obj: T, key: K) => T[K]
80+
>obj : StrNum
81+
>s : unique symbol
82+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// @target: es6
2+
// repro mostly from https://github.com/Microsoft/TypeScript/issues/25065
3+
function getProperty2<T, K extends keyof T>(obj: T, key: Extract<K, string>): T[K] {
4+
return obj[key];
5+
}
6+
7+
function getProperty3<T, K extends Extract<keyof T, string>>(obj: T, key: K): T[K] {
8+
return obj[key];
9+
}
10+
11+
const s = Symbol();
12+
interface StrNum {
13+
first: string;
14+
second: number;
15+
[s]: string;
16+
}
17+
const obj: StrNum = {} as any;
18+
19+
let prop: string;
20+
21+
// should work
22+
prop = getProperty2(obj, 'first');
23+
24+
prop = getProperty3(obj, 'first');
25+
26+
// Should fail
27+
prop = getProperty2(obj, s);
28+
29+
prop = getProperty3(obj, s);

0 commit comments

Comments
 (0)