diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c17893cebe823..2eeea77e49268 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4715,6 +4715,10 @@ namespace ts { return prop ? getTypeOfSymbol(prop) : undefined; } + function getTypeOfPropertyOrIndexSignature(type: Type, name: __String): Type { + return getTypeOfPropertyOfType(type, name) || isNumericLiteralName(name) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String) || unknownType; + } + function isTypeAny(type: Type | undefined) { return type && (type.flags & TypeFlags.Any) !== 0; } @@ -15657,7 +15661,7 @@ namespace ts { } const propType = getTypeOfPropertyOfType(type, propName); const narrowedPropType = propType && narrowType(propType); - return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOfType(t, propName)!, narrowedPropType!)); + return propType === narrowedPropType ? type : filterType(type, t => isTypeComparableTo(getTypeOfPropertyOrIndexSignature(t, propName), narrowedPropType!)); } function narrowTypeByTruthiness(type: Type, expr: Expression, assumeTrue: boolean): Type { diff --git a/tests/baselines/reference/discriminatedUnionTypes2.errors.txt b/tests/baselines/reference/discriminatedUnionTypes2.errors.txt index c50f7a2767aac..15ed6968aeac2 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.errors.txt +++ b/tests/baselines/reference/discriminatedUnionTypes2.errors.txt @@ -83,4 +83,26 @@ tests/cases/conformance/types/union/discriminatedUnionTypes2.ts(32,11): error TS const data: null = carrier.data } } + + // Repro from #28935 + + type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string }; + + function f30(foo: Foo) { + if (foo.tag) { + foo; + } + else { + foo; + } + } + + function f31(foo: Foo) { + if (foo.tag === true) { + foo; + } + else { + foo; + } + } \ No newline at end of file diff --git a/tests/baselines/reference/discriminatedUnionTypes2.js b/tests/baselines/reference/discriminatedUnionTypes2.js index e2b5d99ddcd84..ec5b2a6b5f13f 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.js +++ b/tests/baselines/reference/discriminatedUnionTypes2.js @@ -71,6 +71,28 @@ function f20(carrier: DataCarrier) { const data: null = carrier.data } } + +// Repro from #28935 + +type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string }; + +function f30(foo: Foo) { + if (foo.tag) { + foo; + } + else { + foo; + } +} + +function f31(foo: Foo) { + if (foo.tag === true) { + foo; + } + else { + foo; + } +} //// [discriminatedUnionTypes2.js] @@ -126,3 +148,19 @@ function f20(carrier) { var data = carrier.data; } } +function f30(foo) { + if (foo.tag) { + foo; + } + else { + foo; + } +} +function f31(foo) { + if (foo.tag === true) { + foo; + } + else { + foo; + } +} diff --git a/tests/baselines/reference/discriminatedUnionTypes2.symbols b/tests/baselines/reference/discriminatedUnionTypes2.symbols index 38cfcb0b23ab4..682c62b9be545 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.symbols +++ b/tests/baselines/reference/discriminatedUnionTypes2.symbols @@ -225,3 +225,51 @@ function f20(carrier: DataCarrier) { } } +// Repro from #28935 + +type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string }; +>Foo : Symbol(Foo, Decl(discriminatedUnionTypes2.ts, 71, 1)) +>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12)) +>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 75, 23)) +>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 39)) +>y : Symbol(y, Decl(discriminatedUnionTypes2.ts, 75, 51)) +>x : Symbol(x, Decl(discriminatedUnionTypes2.ts, 75, 69)) + +function f30(foo: Foo) { +>f30 : Symbol(f30, Decl(discriminatedUnionTypes2.ts, 75, 90)) +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13)) +>Foo : Symbol(Foo, Decl(discriminatedUnionTypes2.ts, 71, 1)) + + if (foo.tag) { +>foo.tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39)) +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13)) +>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39)) + + foo; +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13)) + } + else { + foo; +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 77, 13)) + } +} + +function f31(foo: Foo) { +>f31 : Symbol(f31, Decl(discriminatedUnionTypes2.ts, 84, 1)) +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13)) +>Foo : Symbol(Foo, Decl(discriminatedUnionTypes2.ts, 71, 1)) + + if (foo.tag === true) { +>foo.tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39)) +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13)) +>tag : Symbol(tag, Decl(discriminatedUnionTypes2.ts, 75, 12), Decl(discriminatedUnionTypes2.ts, 75, 39)) + + foo; +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13)) + } + else { + foo; +>foo : Symbol(foo, Decl(discriminatedUnionTypes2.ts, 86, 13)) + } +} + diff --git a/tests/baselines/reference/discriminatedUnionTypes2.types b/tests/baselines/reference/discriminatedUnionTypes2.types index b654fc1a78d5c..58819d0d3495a 100644 --- a/tests/baselines/reference/discriminatedUnionTypes2.types +++ b/tests/baselines/reference/discriminatedUnionTypes2.types @@ -239,3 +239,53 @@ function f20(carrier: DataCarrier) { } } +// Repro from #28935 + +type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string }; +>Foo : Foo +>tag : true +>true : true +>x : number +>tag : false +>false : false +>y : number +>x : string + +function f30(foo: Foo) { +>f30 : (foo: Foo) => void +>foo : Foo + + if (foo.tag) { +>foo.tag : string | boolean +>foo : Foo +>tag : string | boolean + + foo; +>foo : { tag: true; x: number; } | { [x: string]: string; } + } + else { + foo; +>foo : { tag: false; y: number; } | { [x: string]: string; } + } +} + +function f31(foo: Foo) { +>f31 : (foo: Foo) => void +>foo : Foo + + if (foo.tag === true) { +>foo.tag === true : boolean +>foo.tag : string | boolean +>foo : Foo +>tag : string | boolean +>true : true + + foo; +>foo : { tag: true; x: number; } + } + else { + foo; +>foo : { tag: false; y: number; } | { [x: string]: string; } + } +} + diff --git a/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts b/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts index 789bc263c7ebc..a11e1447780ee 100644 --- a/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts +++ b/tests/cases/conformance/types/union/discriminatedUnionTypes2.ts @@ -72,3 +72,25 @@ function f20(carrier: DataCarrier) { const data: null = carrier.data } } + +// Repro from #28935 + +type Foo = { tag: true, x: number } | { tag: false, y: number } | { [x: string]: string }; + +function f30(foo: Foo) { + if (foo.tag) { + foo; + } + else { + foo; + } +} + +function f31(foo: Foo) { + if (foo.tag === true) { + foo; + } + else { + foo; + } +}