diff --git a/internal/checker/relater.go b/internal/checker/relater.go index 8da7906566..302861458f 100644 --- a/internal/checker/relater.go +++ b/internal/checker/relater.go @@ -1217,10 +1217,12 @@ func (c *Checker) discriminateTypeByDiscriminableItems(target *Type, discriminat for i := range types { if include[i] != TernaryFalse { targetType := c.getTypeOfPropertyOrIndexSignatureOfType(types[i], discriminator.name(n)) - if targetType != nil && discriminator.matches(n, targetType) { - matched = true - } else { - include[i] = TernaryMaybe + if targetType != nil { + if discriminator.matches(n, targetType) { + matched = true + } else { + include[i] = TernaryMaybe + } } } } diff --git a/testdata/baselines/reference/compiler/missingDiscriminants.errors.txt b/testdata/baselines/reference/compiler/missingDiscriminants.errors.txt new file mode 100644 index 0000000000..33f05ee454 --- /dev/null +++ b/testdata/baselines/reference/compiler/missingDiscriminants.errors.txt @@ -0,0 +1,28 @@ +missingDiscriminants.ts(17,23): error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'. +missingDiscriminants.ts(18,34): error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'. + + +==== missingDiscriminants.ts (2 errors) ==== + // https://github.com/microsoft/typescript-go/issues/1020 + + type Thing = + | { str: "a", num: 0 } + | { str: "b" } + | { num: 1 } + + const thing1: Thing = { str: "a", num: 0 } + const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error + const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error + + type Item = + | { kind: "a", subkind: 0, value: string } + | { kind: "a", subkind: 1, value: number } + | { kind: "b" } + + const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a" + ~~~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'. + const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property + ~~~~~~~ +!!! error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'. + \ No newline at end of file diff --git a/testdata/baselines/reference/compiler/missingDiscriminants.symbols b/testdata/baselines/reference/compiler/missingDiscriminants.symbols new file mode 100644 index 0000000000..53fdcf1096 --- /dev/null +++ b/testdata/baselines/reference/compiler/missingDiscriminants.symbols @@ -0,0 +1,64 @@ +//// [tests/cases/compiler/missingDiscriminants.ts] //// + +=== missingDiscriminants.ts === +// https://github.com/microsoft/typescript-go/issues/1020 + +type Thing = +>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0)) + + | { str: "a", num: 0 } +>str : Symbol(str, Decl(missingDiscriminants.ts, 3, 5)) +>num : Symbol(num, Decl(missingDiscriminants.ts, 3, 15)) + + | { str: "b" } +>str : Symbol(str, Decl(missingDiscriminants.ts, 4, 5)) + + | { num: 1 } +>num : Symbol(num, Decl(missingDiscriminants.ts, 5, 5)) + +const thing1: Thing = { str: "a", num: 0 } +>thing1 : Symbol(thing1, Decl(missingDiscriminants.ts, 7, 5)) +>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0)) +>str : Symbol(str, Decl(missingDiscriminants.ts, 7, 23)) +>num : Symbol(num, Decl(missingDiscriminants.ts, 7, 33)) + +const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error +>thing2 : Symbol(thing2, Decl(missingDiscriminants.ts, 8, 5)) +>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0)) +>str : Symbol(str, Decl(missingDiscriminants.ts, 8, 23)) +>num : Symbol(num, Decl(missingDiscriminants.ts, 8, 33)) + +const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error +>thing3 : Symbol(thing3, Decl(missingDiscriminants.ts, 9, 5)) +>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0)) +>num : Symbol(num, Decl(missingDiscriminants.ts, 9, 23)) +>str : Symbol(str, Decl(missingDiscriminants.ts, 9, 31)) + +type Item = +>Item : Symbol(Item, Decl(missingDiscriminants.ts, 9, 42)) + + | { kind: "a", subkind: 0, value: string } +>kind : Symbol(kind, Decl(missingDiscriminants.ts, 12, 5)) +>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 12, 16)) +>value : Symbol(value, Decl(missingDiscriminants.ts, 12, 28)) + + | { kind: "a", subkind: 1, value: number } +>kind : Symbol(kind, Decl(missingDiscriminants.ts, 13, 5)) +>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 13, 16)) +>value : Symbol(value, Decl(missingDiscriminants.ts, 13, 28)) + + | { kind: "b" } +>kind : Symbol(kind, Decl(missingDiscriminants.ts, 14, 5)) + +const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a" +>item1 : Symbol(item1, Decl(missingDiscriminants.ts, 16, 5)) +>Item : Symbol(Item, Decl(missingDiscriminants.ts, 9, 42)) +>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 16, 21)) +>kind : Symbol(kind, Decl(missingDiscriminants.ts, 16, 33)) + +const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property +>item2 : Symbol(item2, Decl(missingDiscriminants.ts, 17, 5)) +>Item : Symbol(Item, Decl(missingDiscriminants.ts, 9, 42)) +>kind : Symbol(kind, Decl(missingDiscriminants.ts, 17, 21)) +>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 17, 32)) + diff --git a/testdata/baselines/reference/compiler/missingDiscriminants.types b/testdata/baselines/reference/compiler/missingDiscriminants.types new file mode 100644 index 0000000000..8460338504 --- /dev/null +++ b/testdata/baselines/reference/compiler/missingDiscriminants.types @@ -0,0 +1,74 @@ +//// [tests/cases/compiler/missingDiscriminants.ts] //// + +=== missingDiscriminants.ts === +// https://github.com/microsoft/typescript-go/issues/1020 + +type Thing = +>Thing : Thing + + | { str: "a", num: 0 } +>str : "a" +>num : 0 + + | { str: "b" } +>str : "b" + + | { num: 1 } +>num : 1 + +const thing1: Thing = { str: "a", num: 0 } +>thing1 : Thing +>{ str: "a", num: 0 } : { str: "a"; num: 0; } +>str : "a" +>"a" : "a" +>num : 0 +>0 : 0 + +const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error +>thing2 : Thing +>{ str: "b", num: 1 } : { str: "b"; num: 1; } +>str : "b" +>"b" : "b" +>num : 1 +>1 : 1 + +const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error +>thing3 : Thing +>{ num: 1, str: "b" } : { num: 1; str: "b"; } +>num : 1 +>1 : 1 +>str : "b" +>"b" : "b" + +type Item = +>Item : Item + + | { kind: "a", subkind: 0, value: string } +>kind : "a" +>subkind : 0 +>value : string + + | { kind: "a", subkind: 1, value: number } +>kind : "a" +>subkind : 1 +>value : number + + | { kind: "b" } +>kind : "b" + +const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a" +>item1 : Item +>{ subkind: 1, kind: "b" } : { subkind: number; kind: "b"; } +>subkind : number +>1 : 1 +>kind : "b" +>"b" : "b" + +const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property +>item2 : Item +>{ kind: "b", subkind: 1 } : { kind: "b"; subkind: number; } +>kind : "b" +>"b" : "b" +>subkind : number +>1 : 1 + diff --git a/testdata/baselines/reference/submodule/compiler/discriminateWithMissingProperty.errors.txt b/testdata/baselines/reference/submodule/compiler/discriminateWithMissingProperty.errors.txt deleted file mode 100644 index 52ec4ca622..0000000000 --- a/testdata/baselines/reference/submodule/compiler/discriminateWithMissingProperty.errors.txt +++ /dev/null @@ -1,22 +0,0 @@ -discriminateWithMissingProperty.ts(12,5): error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'. - Types of property 'data' are incompatible. - Type 'Uint8Array' is not assignable to type 'number'. - - -==== discriminateWithMissingProperty.ts (1 errors) ==== - type Arg = { - mode: "numeric", - data: number, - } | { - mode: "alphabetic", - data: string, - } | { - data: string | Uint8Array; - } - - declare function foo(arg: Arg): void; - foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'. -!!! error TS2345: Types of property 'data' are incompatible. -!!! error TS2345: Type 'Uint8Array' is not assignable to type 'number'. \ No newline at end of file diff --git a/testdata/baselines/reference/submodule/compiler/discriminateWithMissingProperty.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/discriminateWithMissingProperty.errors.txt.diff new file mode 100644 index 0000000000..892a53eaaf --- /dev/null +++ b/testdata/baselines/reference/submodule/compiler/discriminateWithMissingProperty.errors.txt.diff @@ -0,0 +1,26 @@ +--- old.discriminateWithMissingProperty.errors.txt ++++ new.discriminateWithMissingProperty.errors.txt +@@= skipped -0, +0 lines =@@ +-discriminateWithMissingProperty.ts(12,5): error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'. +- Types of property 'data' are incompatible. +- Type 'Uint8Array' is not assignable to type 'number'. +- +- +-==== discriminateWithMissingProperty.ts (1 errors) ==== +- type Arg = { +- mode: "numeric", +- data: number, +- } | { +- mode: "alphabetic", +- data: string, +- } | { +- data: string | Uint8Array; +- } +- +- declare function foo(arg: Arg): void; +- foo({ mode: "numeric", data: new Uint8Array([30]) }); // Should error +- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-!!! error TS2345: Argument of type '{ mode: "numeric"; data: Uint8Array; }' is not assignable to parameter of type 'Arg'. +-!!! error TS2345: Types of property 'data' are incompatible. +-!!! error TS2345: Type 'Uint8Array' is not assignable to type 'number'. ++ \ No newline at end of file diff --git a/testdata/tests/cases/compiler/missingDiscriminants.ts b/testdata/tests/cases/compiler/missingDiscriminants.ts new file mode 100644 index 0000000000..468b88d28a --- /dev/null +++ b/testdata/tests/cases/compiler/missingDiscriminants.ts @@ -0,0 +1,21 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/typescript-go/issues/1020 + +type Thing = + | { str: "a", num: 0 } + | { str: "b" } + | { num: 1 } + +const thing1: Thing = { str: "a", num: 0 } +const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error +const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error + +type Item = + | { kind: "a", subkind: 0, value: string } + | { kind: "a", subkind: 1, value: number } + | { kind: "b" } + +const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a" +const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property