Skip to content

Commit acfdfe0

Browse files
authored
Merge pull request #10103 from Microsoft/narrowing-a-type-parameter-intersects-concrete-types
Correctly narrow unconstrained type parameters
2 parents 5f665ad + e25db39 commit acfdfe0

File tree

5 files changed

+136
-2
lines changed

5 files changed

+136
-2
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7901,7 +7901,7 @@ namespace ts {
79017901
}
79027902
if (flags & TypeFlags.TypeParameter) {
79037903
const constraint = getConstraintOfTypeParameter(<TypeParameter>type);
7904-
return constraint ? getTypeFacts(constraint) : TypeFacts.All;
7904+
return getTypeFacts(constraint || emptyObjectType);
79057905
}
79067906
if (flags & TypeFlags.UnionOrIntersection) {
79077907
return getTypeFactsOfTypes((<UnionOrIntersectionType>type).types);
@@ -7928,7 +7928,8 @@ namespace ts {
79287928
}
79297929
}
79307930
}
7931-
return firstType ? types ? getUnionType(types) : firstType : neverType;
7931+
return types ? getUnionType(types) :
7932+
firstType ? firstType : neverType;
79327933
}
79337934

79347935
function getTypeWithDefault(type: Type, defaultExpression: Expression) {

tests/baselines/reference/controlFlowIfStatement.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,22 @@ function b() {
3535
}
3636
x; // string
3737
}
38+
function c<T>(data: string | T): T {
39+
if (typeof data === 'string') {
40+
return JSON.parse(data);
41+
}
42+
else {
43+
return data;
44+
}
45+
}
46+
function d<T extends string>(data: string | T): never {
47+
if (typeof data === 'string') {
48+
throw new Error('will always happen');
49+
}
50+
else {
51+
return data;
52+
}
53+
}
3854

3955

4056
//// [controlFlowIfStatement.js]
@@ -72,3 +88,19 @@ function b() {
7288
}
7389
x; // string
7490
}
91+
function c(data) {
92+
if (typeof data === 'string') {
93+
return JSON.parse(data);
94+
}
95+
else {
96+
return data;
97+
}
98+
}
99+
function d(data) {
100+
if (typeof data === 'string') {
101+
throw new Error('will always happen');
102+
}
103+
else {
104+
return data;
105+
}
106+
}

tests/baselines/reference/controlFlowIfStatement.symbols

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,42 @@ function b() {
7171
x; // string
7272
>x : Symbol(x, Decl(controlFlowIfStatement.ts, 26, 7))
7373
}
74+
function c<T>(data: string | T): T {
75+
>c : Symbol(c, Decl(controlFlowIfStatement.ts, 35, 1))
76+
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 36, 11))
77+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 36, 14))
78+
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 36, 11))
79+
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 36, 11))
80+
81+
if (typeof data === 'string') {
82+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 36, 14))
83+
84+
return JSON.parse(data);
85+
>JSON.parse : Symbol(JSON.parse, Decl(lib.d.ts, --, --))
86+
>JSON : Symbol(JSON, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
87+
>parse : Symbol(JSON.parse, Decl(lib.d.ts, --, --))
88+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 36, 14))
89+
}
90+
else {
91+
return data;
92+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 36, 14))
93+
}
94+
}
95+
function d<T extends string>(data: string | T): never {
96+
>d : Symbol(d, Decl(controlFlowIfStatement.ts, 43, 1))
97+
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 44, 11))
98+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 44, 29))
99+
>T : Symbol(T, Decl(controlFlowIfStatement.ts, 44, 11))
100+
101+
if (typeof data === 'string') {
102+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 44, 29))
103+
104+
throw new Error('will always happen');
105+
>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
106+
}
107+
else {
108+
return data;
109+
>data : Symbol(data, Decl(controlFlowIfStatement.ts, 44, 29))
110+
}
111+
}
74112

tests/baselines/reference/controlFlowIfStatement.types

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,51 @@ function b() {
9090
x; // string
9191
>x : string
9292
}
93+
function c<T>(data: string | T): T {
94+
>c : <T>(data: string | T) => T
95+
>T : T
96+
>data : string | T
97+
>T : T
98+
>T : T
99+
100+
if (typeof data === 'string') {
101+
>typeof data === 'string' : boolean
102+
>typeof data : string
103+
>data : string | T
104+
>'string' : "string"
105+
106+
return JSON.parse(data);
107+
>JSON.parse(data) : any
108+
>JSON.parse : (text: string, reviver?: (key: any, value: any) => any) => any
109+
>JSON : JSON
110+
>parse : (text: string, reviver?: (key: any, value: any) => any) => any
111+
>data : string
112+
}
113+
else {
114+
return data;
115+
>data : T
116+
}
117+
}
118+
function d<T extends string>(data: string | T): never {
119+
>d : <T extends string>(data: string | T) => never
120+
>T : T
121+
>data : string | T
122+
>T : T
123+
124+
if (typeof data === 'string') {
125+
>typeof data === 'string' : boolean
126+
>typeof data : string
127+
>data : string | T
128+
>'string' : "string"
129+
130+
throw new Error('will always happen');
131+
>new Error('will always happen') : Error
132+
>Error : ErrorConstructor
133+
>'will always happen' : string
134+
}
135+
else {
136+
return data;
137+
>data : never
138+
}
139+
}
93140

tests/cases/conformance/controlFlow/controlFlowIfStatement.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,19 @@ function b() {
3434
}
3535
x; // string
3636
}
37+
function c<T>(data: string | T): T {
38+
if (typeof data === 'string') {
39+
return JSON.parse(data);
40+
}
41+
else {
42+
return data;
43+
}
44+
}
45+
function d<T extends string>(data: string | T): never {
46+
if (typeof data === 'string') {
47+
throw new Error('will always happen');
48+
}
49+
else {
50+
return data;
51+
}
52+
}

0 commit comments

Comments
 (0)