Skip to content

Commit fbc9c94

Browse files
authored
Normalize target type after null-stripping unions in relationship checks (#43202)
* Normalize target type after null-stripping * Add regression tests
1 parent 451d435 commit fbc9c94

File tree

5 files changed

+186
-2
lines changed

5 files changed

+186
-2
lines changed

src/compiler/checker.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17381,9 +17381,9 @@ namespace ts {
1738117381
(target as UnionType).types.length <= 3 && maybeTypeOfKind(target, TypeFlags.Nullable)) {
1738217382
const nullStrippedTarget = extractTypesOfKind(target, ~TypeFlags.Nullable);
1738317383
if (!(nullStrippedTarget.flags & (TypeFlags.Union | TypeFlags.Never))) {
17384-
if (source === nullStrippedTarget) return Ternary.True;
17385-
target = nullStrippedTarget;
17384+
target = getNormalizedType(nullStrippedTarget, /*writing*/ true);
1738617385
}
17386+
if (source === nullStrippedTarget) return Ternary.True;
1738717387
}
1738817388

1738917389
if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [indexedAccessNormalization.ts]
2+
// Repro from from #43152
3+
4+
type MyMap<M extends object> = {
5+
[K in keyof M]: {
6+
x: number
7+
}
8+
}
9+
10+
declare function g<T>(value?: T): void;
11+
12+
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
13+
const elemofM = mymap[k];
14+
g(elemofM);
15+
}
16+
17+
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
18+
const q1: MyMap<M>[keyof M] = z;
19+
const q2: MyMap<M>[keyof M] | undefined = z;
20+
const q3: MyMap<M>[keyof M] | string = z;
21+
}
22+
23+
24+
//// [indexedAccessNormalization.js]
25+
"use strict";
26+
// Repro from from #43152
27+
function f1(mymap, k) {
28+
var elemofM = mymap[k];
29+
g(elemofM);
30+
}
31+
function f2(mymap, k, z) {
32+
var q1 = z;
33+
var q2 = z;
34+
var q3 = z;
35+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
=== tests/cases/compiler/indexedAccessNormalization.ts ===
2+
// Repro from from #43152
3+
4+
type MyMap<M extends object> = {
5+
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
6+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 2, 11))
7+
8+
[K in keyof M]: {
9+
>K : Symbol(K, Decl(indexedAccessNormalization.ts, 3, 5))
10+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 2, 11))
11+
12+
x: number
13+
>x : Symbol(x, Decl(indexedAccessNormalization.ts, 3, 21))
14+
}
15+
}
16+
17+
declare function g<T>(value?: T): void;
18+
>g : Symbol(g, Decl(indexedAccessNormalization.ts, 6, 1))
19+
>T : Symbol(T, Decl(indexedAccessNormalization.ts, 8, 19))
20+
>value : Symbol(value, Decl(indexedAccessNormalization.ts, 8, 22))
21+
>T : Symbol(T, Decl(indexedAccessNormalization.ts, 8, 19))
22+
23+
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
24+
>f1 : Symbol(f1, Decl(indexedAccessNormalization.ts, 8, 39))
25+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 10, 12))
26+
>mymap : Symbol(mymap, Decl(indexedAccessNormalization.ts, 10, 30))
27+
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
28+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 10, 12))
29+
>k : Symbol(k, Decl(indexedAccessNormalization.ts, 10, 46))
30+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 10, 12))
31+
32+
const elemofM = mymap[k];
33+
>elemofM : Symbol(elemofM, Decl(indexedAccessNormalization.ts, 11, 9))
34+
>mymap : Symbol(mymap, Decl(indexedAccessNormalization.ts, 10, 30))
35+
>k : Symbol(k, Decl(indexedAccessNormalization.ts, 10, 46))
36+
37+
g(elemofM);
38+
>g : Symbol(g, Decl(indexedAccessNormalization.ts, 6, 1))
39+
>elemofM : Symbol(elemofM, Decl(indexedAccessNormalization.ts, 11, 9))
40+
}
41+
42+
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
43+
>f2 : Symbol(f2, Decl(indexedAccessNormalization.ts, 13, 1))
44+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
45+
>mymap : Symbol(mymap, Decl(indexedAccessNormalization.ts, 15, 30))
46+
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
47+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
48+
>k : Symbol(k, Decl(indexedAccessNormalization.ts, 15, 46))
49+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
50+
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
51+
>x : Symbol(x, Decl(indexedAccessNormalization.ts, 15, 63))
52+
53+
const q1: MyMap<M>[keyof M] = z;
54+
>q1 : Symbol(q1, Decl(indexedAccessNormalization.ts, 16, 9))
55+
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
56+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
57+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
58+
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
59+
60+
const q2: MyMap<M>[keyof M] | undefined = z;
61+
>q2 : Symbol(q2, Decl(indexedAccessNormalization.ts, 17, 9))
62+
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
63+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
64+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
65+
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
66+
67+
const q3: MyMap<M>[keyof M] | string = z;
68+
>q3 : Symbol(q3, Decl(indexedAccessNormalization.ts, 18, 9))
69+
>MyMap : Symbol(MyMap, Decl(indexedAccessNormalization.ts, 0, 0))
70+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
71+
>M : Symbol(M, Decl(indexedAccessNormalization.ts, 15, 12))
72+
>z : Symbol(z, Decl(indexedAccessNormalization.ts, 15, 58))
73+
}
74+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
=== tests/cases/compiler/indexedAccessNormalization.ts ===
2+
// Repro from from #43152
3+
4+
type MyMap<M extends object> = {
5+
>MyMap : MyMap<M>
6+
7+
[K in keyof M]: {
8+
x: number
9+
>x : number
10+
}
11+
}
12+
13+
declare function g<T>(value?: T): void;
14+
>g : <T>(value?: T | undefined) => void
15+
>value : T | undefined
16+
17+
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
18+
>f1 : <M extends object>(mymap: MyMap<M>, k: keyof M) => void
19+
>mymap : MyMap<M>
20+
>k : keyof M
21+
22+
const elemofM = mymap[k];
23+
>elemofM : MyMap<M>[keyof M]
24+
>mymap[k] : MyMap<M>[keyof M]
25+
>mymap : MyMap<M>
26+
>k : keyof M
27+
28+
g(elemofM);
29+
>g(elemofM) : void
30+
>g : <T>(value?: T | undefined) => void
31+
>elemofM : MyMap<M>[keyof M]
32+
}
33+
34+
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
35+
>f2 : <M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number;}) => void
36+
>mymap : MyMap<M>
37+
>k : keyof M
38+
>z : { x: number; }
39+
>x : number
40+
41+
const q1: MyMap<M>[keyof M] = z;
42+
>q1 : MyMap<M>[keyof M]
43+
>z : { x: number; }
44+
45+
const q2: MyMap<M>[keyof M] | undefined = z;
46+
>q2 : MyMap<M>[keyof M] | undefined
47+
>z : { x: number; }
48+
49+
const q3: MyMap<M>[keyof M] | string = z;
50+
>q3 : string | MyMap<M>[keyof M]
51+
>z : { x: number; }
52+
}
53+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @strict: true
2+
3+
// Repro from from #43152
4+
5+
type MyMap<M extends object> = {
6+
[K in keyof M]: {
7+
x: number
8+
}
9+
}
10+
11+
declare function g<T>(value?: T): void;
12+
13+
function f1<M extends object>(mymap: MyMap<M>, k: keyof M) {
14+
const elemofM = mymap[k];
15+
g(elemofM);
16+
}
17+
18+
function f2<M extends object>(mymap: MyMap<M>, k: keyof M, z: { x: number }) {
19+
const q1: MyMap<M>[keyof M] = z;
20+
const q2: MyMap<M>[keyof M] | undefined = z;
21+
const q3: MyMap<M>[keyof M] | string = z;
22+
}

0 commit comments

Comments
 (0)