Skip to content

Commit 0127a18

Browse files
committed
Port "Improve type discrimination algorithm" from tsgo (#61828)
1 parent 746c232 commit 0127a18

File tree

8 files changed

+239
-29
lines changed

8 files changed

+239
-29
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24244,11 +24244,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2424424244
for (let i = 0; i < types.length; i++) {
2424524245
if (include[i]) {
2424624246
const targetType = getTypeOfPropertyOrIndexSignatureOfType(types[i], propertyName);
24247-
if (targetType && someType(getDiscriminatingType(), t => !!related(t, targetType))) {
24248-
matched = true;
24249-
}
24250-
else {
24251-
include[i] = Ternary.Maybe;
24247+
if (targetType) {
24248+
if (someType(getDiscriminatingType(), t => !!related(t, targetType))) {
24249+
matched = true;
24250+
}
24251+
else {
24252+
include[i] = Ternary.Maybe;
24253+
}
2425224254
}
2425324255
}
2425424256
}

src/services/codefixes/importFixes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ function createImportAdderWorker(sourceFile: SourceFile | FutureSourceFile, prog
370370
);
371371

372372
let fix: FixAddNewImport | ImportFixWithModuleSpecifier;
373-
if (existingFix && importKind !== ImportKind.Namespace) {
373+
if (existingFix && importKind !== ImportKind.Namespace && existingFix.kind !== ImportFixKind.UseNamespace && existingFix.kind !== ImportFixKind.JsdocTypeImport) {
374374
fix = {
375375
...existingFix,
376376
addAsTypeOnly,

tests/baselines/reference/discriminateWithMissingProperty.errors.txt

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
missingDiscriminants.ts(17,23): error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'.
2+
missingDiscriminants.ts(18,34): error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'.
3+
4+
5+
==== missingDiscriminants.ts (2 errors) ====
6+
// https://github.com/microsoft/typescript-go/issues/1020
7+
8+
type Thing =
9+
| { str: "a", num: 0 }
10+
| { str: "b" }
11+
| { num: 1 }
12+
13+
const thing1: Thing = { str: "a", num: 0 }
14+
const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error
15+
const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error
16+
17+
type Item =
18+
| { kind: "a", subkind: 0, value: string }
19+
| { kind: "a", subkind: 1, value: number }
20+
| { kind: "b" }
21+
22+
const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a"
23+
~~~~~~~
24+
!!! error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'.
25+
const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property
26+
~~~~~~~
27+
!!! error TS2353: Object literal may only specify known properties, and 'subkind' does not exist in type '{ kind: "b"; }'.
28+
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//// [tests/cases/compiler/missingDiscriminants.ts] ////
2+
3+
=== missingDiscriminants.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/1020
5+
6+
type Thing =
7+
>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0))
8+
9+
| { str: "a", num: 0 }
10+
>str : Symbol(str, Decl(missingDiscriminants.ts, 3, 5))
11+
>num : Symbol(num, Decl(missingDiscriminants.ts, 3, 15))
12+
13+
| { str: "b" }
14+
>str : Symbol(str, Decl(missingDiscriminants.ts, 4, 5))
15+
16+
| { num: 1 }
17+
>num : Symbol(num, Decl(missingDiscriminants.ts, 5, 5))
18+
19+
const thing1: Thing = { str: "a", num: 0 }
20+
>thing1 : Symbol(thing1, Decl(missingDiscriminants.ts, 7, 5))
21+
>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0))
22+
>str : Symbol(str, Decl(missingDiscriminants.ts, 7, 23))
23+
>num : Symbol(num, Decl(missingDiscriminants.ts, 7, 33))
24+
25+
const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error
26+
>thing2 : Symbol(thing2, Decl(missingDiscriminants.ts, 8, 5))
27+
>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0))
28+
>str : Symbol(str, Decl(missingDiscriminants.ts, 8, 23))
29+
>num : Symbol(num, Decl(missingDiscriminants.ts, 8, 33))
30+
31+
const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error
32+
>thing3 : Symbol(thing3, Decl(missingDiscriminants.ts, 9, 5))
33+
>Thing : Symbol(Thing, Decl(missingDiscriminants.ts, 0, 0))
34+
>num : Symbol(num, Decl(missingDiscriminants.ts, 9, 23))
35+
>str : Symbol(str, Decl(missingDiscriminants.ts, 9, 31))
36+
37+
type Item =
38+
>Item : Symbol(Item, Decl(missingDiscriminants.ts, 9, 42))
39+
40+
| { kind: "a", subkind: 0, value: string }
41+
>kind : Symbol(kind, Decl(missingDiscriminants.ts, 12, 5))
42+
>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 12, 16))
43+
>value : Symbol(value, Decl(missingDiscriminants.ts, 12, 28))
44+
45+
| { kind: "a", subkind: 1, value: number }
46+
>kind : Symbol(kind, Decl(missingDiscriminants.ts, 13, 5))
47+
>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 13, 16))
48+
>value : Symbol(value, Decl(missingDiscriminants.ts, 13, 28))
49+
50+
| { kind: "b" }
51+
>kind : Symbol(kind, Decl(missingDiscriminants.ts, 14, 5))
52+
53+
const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a"
54+
>item1 : Symbol(item1, Decl(missingDiscriminants.ts, 16, 5))
55+
>Item : Symbol(Item, Decl(missingDiscriminants.ts, 9, 42))
56+
>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 16, 21))
57+
>kind : Symbol(kind, Decl(missingDiscriminants.ts, 16, 33))
58+
59+
const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property
60+
>item2 : Symbol(item2, Decl(missingDiscriminants.ts, 17, 5))
61+
>Item : Symbol(Item, Decl(missingDiscriminants.ts, 9, 42))
62+
>kind : Symbol(kind, Decl(missingDiscriminants.ts, 17, 21))
63+
>subkind : Symbol(subkind, Decl(missingDiscriminants.ts, 17, 32))
64+
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//// [tests/cases/compiler/missingDiscriminants.ts] ////
2+
3+
=== missingDiscriminants.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/1020
5+
6+
type Thing =
7+
>Thing : Thing
8+
> : ^^^^^
9+
10+
| { str: "a", num: 0 }
11+
>str : "a"
12+
> : ^^^
13+
>num : 0
14+
> : ^
15+
16+
| { str: "b" }
17+
>str : "b"
18+
> : ^^^
19+
20+
| { num: 1 }
21+
>num : 1
22+
> : ^
23+
24+
const thing1: Thing = { str: "a", num: 0 }
25+
>thing1 : Thing
26+
> : ^^^^^
27+
>{ str: "a", num: 0 } : { str: "a"; num: 0; }
28+
> : ^^^^^^^^^^^^^^^^^^^^^
29+
>str : "a"
30+
> : ^^^
31+
>"a" : "a"
32+
> : ^^^
33+
>num : 0
34+
> : ^
35+
>0 : 0
36+
> : ^
37+
38+
const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error
39+
>thing2 : Thing
40+
> : ^^^^^
41+
>{ str: "b", num: 1 } : { str: "b"; num: 1; }
42+
> : ^^^^^^^^^^^^^^^^^^^^^
43+
>str : "b"
44+
> : ^^^
45+
>"b" : "b"
46+
> : ^^^
47+
>num : 1
48+
> : ^
49+
>1 : 1
50+
> : ^
51+
52+
const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error
53+
>thing3 : Thing
54+
> : ^^^^^
55+
>{ num: 1, str: "b" } : { num: 1; str: "b"; }
56+
> : ^^^^^^^^^^^^^^^^^^^^^
57+
>num : 1
58+
> : ^
59+
>1 : 1
60+
> : ^
61+
>str : "b"
62+
> : ^^^
63+
>"b" : "b"
64+
> : ^^^
65+
66+
type Item =
67+
>Item : Item
68+
> : ^^^^
69+
70+
| { kind: "a", subkind: 0, value: string }
71+
>kind : "a"
72+
> : ^^^
73+
>subkind : 0
74+
> : ^
75+
>value : string
76+
> : ^^^^^^
77+
78+
| { kind: "a", subkind: 1, value: number }
79+
>kind : "a"
80+
> : ^^^
81+
>subkind : 1
82+
> : ^
83+
>value : number
84+
> : ^^^^^^
85+
86+
| { kind: "b" }
87+
>kind : "b"
88+
> : ^^^
89+
90+
const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a"
91+
>item1 : Item
92+
> : ^^^^
93+
>{ subkind: 1, kind: "b" } : { subkind: number; kind: "b"; }
94+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
95+
>subkind : number
96+
> : ^^^^^^
97+
>1 : 1
98+
> : ^
99+
>kind : "b"
100+
> : ^^^
101+
>"b" : "b"
102+
> : ^^^
103+
104+
const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property
105+
>item2 : Item
106+
> : ^^^^
107+
>{ kind: "b", subkind: 1 } : { kind: "b"; subkind: number; }
108+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109+
>kind : "b"
110+
> : ^^^
111+
>"b" : "b"
112+
> : ^^^
113+
>subkind : number
114+
> : ^^^^^^
115+
>1 : 1
116+
> : ^
117+

tests/baselines/reference/promiseType.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//// [tests/cases/compiler/promiseType.ts] ////
22

33
=== Performance Stats ===
4-
Instantiation count: 2,500
4+
Instantiation count: 1,000
55

66
=== promiseType.ts ===
77
declare var p: Promise<boolean>;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/typescript-go/issues/1020
5+
6+
type Thing =
7+
| { str: "a", num: 0 }
8+
| { str: "b" }
9+
| { num: 1 }
10+
11+
const thing1: Thing = { str: "a", num: 0 }
12+
const thing2: Thing = { str: "b", num: 1 } // Shouldn't be error
13+
const thing3: Thing = { num: 1, str: "b" } // Shouldn't be error
14+
15+
type Item =
16+
| { kind: "a", subkind: 0, value: string }
17+
| { kind: "a", subkind: 1, value: number }
18+
| { kind: "b" }
19+
20+
const item1: Item = { subkind: 1, kind: "b" } // Error, type "b" not assignable to type "a"
21+
const item2: Item = { kind: "b", subkind: 1 } // Error, 'subkind' isn't a known property

0 commit comments

Comments
 (0)