Port microsoft/typescript-go#1757 (#62501)

This commit is contained in:
Anders Hejlsberg
2025-09-29 14:42:29 -07:00
committed by GitHub
parent 1cd5309f7d
commit 97610a8a63
5 changed files with 362 additions and 17 deletions

View File

@@ -27885,24 +27885,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;

View File

@@ -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"; }'.

View File

@@ -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))

View File

@@ -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
> : ^

View File

@@ -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