diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 10376e268a4f0..5c53409dcaa09 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -27888,24 +27888,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { for (const type of types) { if (type.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.InstantiableNonPrimitive)) { const discriminant = getTypeOfPropertyOfType(type, name); - if (discriminant) { - if (!isLiteralType(discriminant)) { - return undefined; - } - let duplicate = false; - forEachType(discriminant, t => { - const id = getTypeId(getRegularTypeOfLiteralType(t)); - const existing = map.get(id); - if (!existing) { - map.set(id, type); - } - else if (existing !== unknownType) { - map.set(id, unknownType); - duplicate = true; - } - }); - if (!duplicate) count++; + if (!discriminant || !isLiteralType(discriminant)) { + return undefined; } + let duplicate = false; + forEachType(discriminant, t => { + const id = getTypeId(getRegularTypeOfLiteralType(t)); + const existing = map.get(id); + if (!existing) { + map.set(id, type); + } + else if (existing !== unknownType) { + map.set(id, unknownType); + duplicate = true; + } + }); + if (!duplicate) count++; } } return count >= 10 && count * 2 >= types.length ? map : undefined; diff --git a/tests/baselines/reference/missingDiscriminants2.errors.txt b/tests/baselines/reference/missingDiscriminants2.errors.txt new file mode 100644 index 0000000000000..89852e50c4fde --- /dev/null +++ b/tests/baselines/reference/missingDiscriminants2.errors.txt @@ -0,0 +1,41 @@ +missingDiscriminants2.ts(30,23): error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'. +missingDiscriminants2.ts(31,34): error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'. + + +==== missingDiscriminants2.ts (2 errors) ==== + // https://github.com/microsoft/typescript-go/issues/1020 + + type Thing = + | { str: "a", num: 0 } + | { str: "b" } + | { str: "c" } + | { str: "d" } + | { str: "e" } + | { str: "f" } + | { str: "g" } + | { str: "h" } + | { str: "i" } + | { str: "j" } + | { str: "k" } + | { str: "l" } + | { str: "m" } + | { str: "n" } + | { str: "o" } + | { 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/tests/baselines/reference/missingDiscriminants2.symbols b/tests/baselines/reference/missingDiscriminants2.symbols new file mode 100644 index 0000000000000..c05c01668c2c7 --- /dev/null +++ b/tests/baselines/reference/missingDiscriminants2.symbols @@ -0,0 +1,103 @@ +//// [tests/cases/compiler/missingDiscriminants2.ts] //// + +=== missingDiscriminants2.ts === +// https://github.com/microsoft/typescript-go/issues/1020 + +type Thing = +>Thing : Symbol(Thing, Decl(missingDiscriminants2.ts, 0, 0)) + + | { str: "a", num: 0 } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 3, 5)) +>num : Symbol(num, Decl(missingDiscriminants2.ts, 3, 15)) + + | { str: "b" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 4, 5)) + + | { str: "c" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 5, 5)) + + | { str: "d" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 6, 5)) + + | { str: "e" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 7, 5)) + + | { str: "f" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 8, 5)) + + | { str: "g" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 9, 5)) + + | { str: "h" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 10, 5)) + + | { str: "i" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 11, 5)) + + | { str: "j" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 12, 5)) + + | { str: "k" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 13, 5)) + + | { str: "l" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 14, 5)) + + | { str: "m" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 15, 5)) + + | { str: "n" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 16, 5)) + + | { str: "o" } +>str : Symbol(str, Decl(missingDiscriminants2.ts, 17, 5)) + + | { num: 1 } +>num : Symbol(num, Decl(missingDiscriminants2.ts, 18, 5)) + +const thing1: Thing = { str: "a", num: 0 } +>thing1 : Symbol(thing1, Decl(missingDiscriminants2.ts, 20, 5)) +>Thing : Symbol(Thing, Decl(missingDiscriminants2.ts, 0, 0)) +>str : Symbol(str, Decl(missingDiscriminants2.ts, 20, 23)) +>num : Symbol(num, Decl(missingDiscriminants2.ts, 20, 33)) + +const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error +>thing2 : Symbol(thing2, Decl(missingDiscriminants2.ts, 21, 5)) +>Thing : Symbol(Thing, Decl(missingDiscriminants2.ts, 0, 0)) +>str : Symbol(str, Decl(missingDiscriminants2.ts, 21, 23)) +>num : Symbol(num, Decl(missingDiscriminants2.ts, 21, 33)) + +const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error +>thing3 : Symbol(thing3, Decl(missingDiscriminants2.ts, 22, 5)) +>Thing : Symbol(Thing, Decl(missingDiscriminants2.ts, 0, 0)) +>num : Symbol(num, Decl(missingDiscriminants2.ts, 22, 23)) +>str : Symbol(str, Decl(missingDiscriminants2.ts, 22, 31)) + +type Item = +>Item : Symbol(Item, Decl(missingDiscriminants2.ts, 22, 42)) + + | { kind: "a", subkind: 0, value: string } +>kind : Symbol(kind, Decl(missingDiscriminants2.ts, 25, 5)) +>subkind : Symbol(subkind, Decl(missingDiscriminants2.ts, 25, 16)) +>value : Symbol(value, Decl(missingDiscriminants2.ts, 25, 28)) + + | { kind: "a", subkind: 1, value: number } +>kind : Symbol(kind, Decl(missingDiscriminants2.ts, 26, 5)) +>subkind : Symbol(subkind, Decl(missingDiscriminants2.ts, 26, 16)) +>value : Symbol(value, Decl(missingDiscriminants2.ts, 26, 28)) + + | { kind: "b" } +>kind : Symbol(kind, Decl(missingDiscriminants2.ts, 27, 5)) + +const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a" +>item1 : Symbol(item1, Decl(missingDiscriminants2.ts, 29, 5)) +>Item : Symbol(Item, Decl(missingDiscriminants2.ts, 22, 42)) +>subkind : Symbol(subkind, Decl(missingDiscriminants2.ts, 29, 21)) +>kind : Symbol(kind, Decl(missingDiscriminants2.ts, 29, 33)) + +const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property +>item2 : Symbol(item2, Decl(missingDiscriminants2.ts, 30, 5)) +>Item : Symbol(Item, Decl(missingDiscriminants2.ts, 22, 42)) +>kind : Symbol(kind, Decl(missingDiscriminants2.ts, 30, 21)) +>subkind : Symbol(subkind, Decl(missingDiscriminants2.ts, 30, 32)) + diff --git a/tests/baselines/reference/missingDiscriminants2.types b/tests/baselines/reference/missingDiscriminants2.types new file mode 100644 index 0000000000000..10d00c873ce26 --- /dev/null +++ b/tests/baselines/reference/missingDiscriminants2.types @@ -0,0 +1,169 @@ +//// [tests/cases/compiler/missingDiscriminants2.ts] //// + +=== missingDiscriminants2.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" +> : ^^^ + + | { str: "c" } +>str : "c" +> : ^^^ + + | { str: "d" } +>str : "d" +> : ^^^ + + | { str: "e" } +>str : "e" +> : ^^^ + + | { str: "f" } +>str : "f" +> : ^^^ + + | { str: "g" } +>str : "g" +> : ^^^ + + | { str: "h" } +>str : "h" +> : ^^^ + + | { str: "i" } +>str : "i" +> : ^^^ + + | { str: "j" } +>str : "j" +> : ^^^ + + | { str: "k" } +>str : "k" +> : ^^^ + + | { str: "l" } +>str : "l" +> : ^^^ + + | { str: "m" } +>str : "m" +> : ^^^ + + | { str: "n" } +>str : "n" +> : ^^^ + + | { str: "o" } +>str : "o" +> : ^^^ + + | { 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/tests/cases/compiler/missingDiscriminants2.ts b/tests/cases/compiler/missingDiscriminants2.ts new file mode 100644 index 0000000000000..ca42b76ff2794 --- /dev/null +++ b/tests/cases/compiler/missingDiscriminants2.ts @@ -0,0 +1,34 @@ +// @strict: true +// @noEmit: true + +// https://github.com/microsoft/typescript-go/issues/1020 + +type Thing = + | { str: "a", num: 0 } + | { str: "b" } + | { str: "c" } + | { str: "d" } + | { str: "e" } + | { str: "f" } + | { str: "g" } + | { str: "h" } + | { str: "i" } + | { str: "j" } + | { str: "k" } + | { str: "l" } + | { str: "m" } + | { str: "n" } + | { str: "o" } + | { 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