Skip to content

Commit c5c4908

Browse files
authored
Merge pull request #28948 from Microsoft/discriminatedUnionIndexSignature
Fix crash related to discriminated unions with index signatures
2 parents b99c60a + aa9db9a commit c5c4908

File tree

6 files changed

+185
-1
lines changed

6 files changed

+185
-1
lines changed

src/compiler/checker.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4715,6 +4715,10 @@ namespace ts {
47154715
return prop ? getTypeOfSymbol(prop) : undefined;
47164716
}
47174717

4718+
function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type {
4719+
return getTypeOfPropertyOfType(type, name) || isNumericLiteralName(name) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String) || unknownType;
4720+
}
4721+
47184722
function isTypeAny(type: Type | undefined) {
47194723
return type && (type.flags & TypeFlags.Any) !== 0;
47204724
}
@@ -15657,7 +15661,7 @@ namespace ts {
1565715661
}
1565815662
const propType = getTypeOfPropertyOfType(type, propName);
1565915663
const narrowedPropType = propType && narrowType(propType);
15660-
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOfType(t, propName)!, narrowedPropType!));
15664+
return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOrIndexSignature(t, propName), narrowedPropType!));
1566115665
}
1566215666

1566315667
function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type {

tests/baselines/reference/discriminatedUnionTypes2.errors.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,26 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS
8383
const data: null = carrier.data
8484
}
8585
}
86+
87+
// Repro from #28935
88+
89+
type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string };
90+
91+
function f30(foo: Foo) {
92+
if (foo.tag) {
93+
foo;
94+
}
95+
else {
96+
foo;
97+
}
98+
}
99+
100+
function f31(foo: Foo) {
101+
if (foo.tag === true) {
102+
foo;
103+
}
104+
else {
105+
foo;
106+
}
107+
}
86108

tests/baselines/reference/discriminatedUnionTypes2.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,28 @@ function f20<Data>(carrier: DataCarrier<Data>) {
7171
const data: null = carrier.data
7272
}
7373
}
74+
75+
// Repro from #28935
76+
77+
type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string };
78+
79+
function f30(foo: Foo) {
80+
if (foo.tag) {
81+
foo;
82+
}
83+
else {
84+
foo;
85+
}
86+
}
87+
88+
function f31(foo: Foo) {
89+
if (foo.tag === true) {
90+
foo;
91+
}
92+
else {
93+
foo;
94+
}
95+
}
7496

7597

7698
//// [discriminatedUnionTypes2.js]
@@ -126,3 +148,19 @@ function f20(carrier) {
126148
var data = carrier.data;
127149
}
128150
}
151+
function f30(foo) {
152+
if (foo.tag) {
153+
foo;
154+
}
155+
else {
156+
foo;
157+
}
158+
}
159+
function f31(foo) {
160+
if (foo.tag === true) {
161+
foo;
162+
}
163+
else {
164+
foo;
165+
}
166+
}

tests/baselines/reference/discriminatedUnionTypes2.symbols

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,51 @@ function f20<Data>(carrier: DataCarrier<Data>) {
225225
}
226226
}
227227

228+
// Repro from #28935
229+
230+
type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string };
231+
>Foo : Symbol(Foo, Decl(discriminatedUnionTypes2.ts, 71, 1))
232+
>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12))
233+
>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 75, 23))
234+
>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 39))
235+
>y : Symbol(y, Decl(discriminatedUnionTypes2.ts, 75, 51))
236+
>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 75, 69))
237+
238+
function f30(foo: Foo) {
239+
>f30 : Symbol(f30, Decl(discriminatedUnionTypes2.ts, 75, 90))
240+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13))
241+
>Foo : Symbol(Foo, Decl(discriminatedUnionTypes2.ts, 71, 1))
242+
243+
if (foo.tag) {
244+
>foo.tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39))
245+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13))
246+
>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39))
247+
248+
foo;
249+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13))
250+
}
251+
else {
252+
foo;
253+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13))
254+
}
255+
}
256+
257+
function f31(foo: Foo) {
258+
>f31 : Symbol(f31, Decl(discriminatedUnionTypes2.ts, 84, 1))
259+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13))
260+
>Foo : Symbol(Foo, Decl(discriminatedUnionTypes2.ts, 71, 1))
261+
262+
if (foo.tag === true) {
263+
>foo.tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39))
264+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13))
265+
>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39))
266+
267+
foo;
268+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13))
269+
}
270+
else {
271+
foo;
272+
>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13))
273+
}
274+
}
275+

tests/baselines/reference/discriminatedUnionTypes2.types

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,53 @@ function f20<Data>(carrier: DataCarrier<Data>) {
239239
}
240240
}
241241

242+
// Repro from #28935
243+
244+
type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string };
245+
>Foo : Foo
246+
>tag : true
247+
>true : true
248+
>x : number
249+
>tag : false
250+
>false : false
251+
>y : number
252+
>x : string
253+
254+
function f30(foo: Foo) {
255+
>f30 : (foo: Foo) => void
256+
>foo : Foo
257+
258+
if (foo.tag) {
259+
>foo.tag : string | boolean
260+
>foo : Foo
261+
>tag : string | boolean
262+
263+
foo;
264+
>foo : { tag: true; x: number; } | { [x: string]: string; }
265+
}
266+
else {
267+
foo;
268+
>foo : { tag: false; y: number; } | { [x: string]: string; }
269+
}
270+
}
271+
272+
function f31(foo: Foo) {
273+
>f31 : (foo: Foo) => void
274+
>foo : Foo
275+
276+
if (foo.tag === true) {
277+
>foo.tag === true : boolean
278+
>foo.tag : string | boolean
279+
>foo : Foo
280+
>tag : string | boolean
281+
>true : true
282+
283+
foo;
284+
>foo : { tag: true; x: number; }
285+
}
286+
else {
287+
foo;
288+
>foo : { tag: false; y: number; } | { [x: string]: string; }
289+
}
290+
}
291+

tests/cases/conformance/types/union/discriminatedUnionTypes2.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,25 @@ function f20<Data>(carrier: DataCarrier<Data>) {
7272
const data: null = carrier.data
7373
}
7474
}
75+
76+
// Repro from #28935
77+
78+
type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string };
79+
80+
function f30(foo: Foo) {
81+
if (foo.tag) {
82+
foo;
83+
}
84+
else {
85+
foo;
86+
}
87+
}
88+
89+
function f31(foo: Foo) {
90+
if (foo.tag === true) {
91+
foo;
92+
}
93+
else {
94+
foo;
95+
}
96+
}

0 commit comments

Comments
 (0)