Skip to content

Commit a70bb9d

Browse files
authored
Preserve special intersections in mapped types (#50704)
* Preserve special intersections in mapped types * Add regression test
1 parent 1a1c271 commit a70bb9d

6 files changed

+158
-0
lines changed

src/compiler/checker.ts

+6
Original file line numberDiff line numberDiff line change
@@ -11780,6 +11780,12 @@ namespace ts {
1178011780
return mapType(type as UnionType, getLowerBoundOfKeyType);
1178111781
}
1178211782
if (type.flags & TypeFlags.Intersection) {
11783+
// Similarly to getTypeFromIntersectionTypeNode, we preserve the special string & {}, number & {},
11784+
// and bigint & {} intersections that are used to prevent subtype reduction in union types.
11785+
const types = (type as IntersectionType).types;
11786+
if (types.length === 2 && !!(types[0].flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.BigInt)) && types[1] === emptyTypeLiteralType) {
11787+
return type;
11788+
}
1178311789
return getIntersectionType(sameMap((type as UnionType).types, getLowerBoundOfKeyType));
1178411790
}
1178511791
return type;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
tests/cases/compiler/specialIntersectionsInMappedTypes.ts(14,1): error TS2532: Object is possibly 'undefined'.
2+
3+
4+
==== tests/cases/compiler/specialIntersectionsInMappedTypes.ts (1 errors) ====
5+
// Repro from #50683
6+
7+
type Alignment = (string & {}) | "left" | "center" | "right";
8+
type Alignments = Record<Alignment, string>;
9+
10+
const a: Alignments = {
11+
left: "align-left",
12+
center: "align-center",
13+
right: "align-right",
14+
other: "align-other",
15+
};
16+
17+
a.left.length;
18+
a.other.length; // Error expected here
19+
~~~~~~~
20+
!!! error TS2532: Object is possibly 'undefined'.
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//// [specialIntersectionsInMappedTypes.ts]
2+
// Repro from #50683
3+
4+
type Alignment = (string & {}) | "left" | "center" | "right";
5+
type Alignments = Record<Alignment, string>;
6+
7+
const a: Alignments = {
8+
left: "align-left",
9+
center: "align-center",
10+
right: "align-right",
11+
other: "align-other",
12+
};
13+
14+
a.left.length;
15+
a.other.length; // Error expected here
16+
17+
18+
//// [specialIntersectionsInMappedTypes.js]
19+
"use strict";
20+
// Repro from #50683
21+
var a = {
22+
left: "align-left",
23+
center: "align-center",
24+
right: "align-right",
25+
other: "align-other"
26+
};
27+
a.left.length;
28+
a.other.length; // Error expected here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
=== tests/cases/compiler/specialIntersectionsInMappedTypes.ts ===
2+
// Repro from #50683
3+
4+
type Alignment = (string & {}) | "left" | "center" | "right";
5+
>Alignment : Symbol(Alignment, Decl(specialIntersectionsInMappedTypes.ts, 0, 0))
6+
7+
type Alignments = Record<Alignment, string>;
8+
>Alignments : Symbol(Alignments, Decl(specialIntersectionsInMappedTypes.ts, 2, 61))
9+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
10+
>Alignment : Symbol(Alignment, Decl(specialIntersectionsInMappedTypes.ts, 0, 0))
11+
12+
const a: Alignments = {
13+
>a : Symbol(a, Decl(specialIntersectionsInMappedTypes.ts, 5, 5))
14+
>Alignments : Symbol(Alignments, Decl(specialIntersectionsInMappedTypes.ts, 2, 61))
15+
16+
left: "align-left",
17+
>left : Symbol(left, Decl(specialIntersectionsInMappedTypes.ts, 5, 23))
18+
19+
center: "align-center",
20+
>center : Symbol(center, Decl(specialIntersectionsInMappedTypes.ts, 6, 23))
21+
22+
right: "align-right",
23+
>right : Symbol(right, Decl(specialIntersectionsInMappedTypes.ts, 7, 27))
24+
25+
other: "align-other",
26+
>other : Symbol(other, Decl(specialIntersectionsInMappedTypes.ts, 8, 25))
27+
28+
};
29+
30+
a.left.length;
31+
>a.left.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
32+
>a.left : Symbol(left)
33+
>a : Symbol(a, Decl(specialIntersectionsInMappedTypes.ts, 5, 5))
34+
>left : Symbol(left)
35+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
36+
37+
a.other.length; // Error expected here
38+
>a.other.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
39+
>a : Symbol(a, Decl(specialIntersectionsInMappedTypes.ts, 5, 5))
40+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
41+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
=== tests/cases/compiler/specialIntersectionsInMappedTypes.ts ===
2+
// Repro from #50683
3+
4+
type Alignment = (string & {}) | "left" | "center" | "right";
5+
>Alignment : (string & {}) | "left" | "center" | "right"
6+
7+
type Alignments = Record<Alignment, string>;
8+
>Alignments : { [x: string & {}]: string; left: string; center: string; right: string; }
9+
10+
const a: Alignments = {
11+
>a : Alignments
12+
>{ left: "align-left", center: "align-center", right: "align-right", other: "align-other",} : { left: string; center: string; right: string; other: string; }
13+
14+
left: "align-left",
15+
>left : string
16+
>"align-left" : "align-left"
17+
18+
center: "align-center",
19+
>center : string
20+
>"align-center" : "align-center"
21+
22+
right: "align-right",
23+
>right : string
24+
>"align-right" : "align-right"
25+
26+
other: "align-other",
27+
>other : string
28+
>"align-other" : "align-other"
29+
30+
};
31+
32+
a.left.length;
33+
>a.left.length : number
34+
>a.left : string
35+
>a : Alignments
36+
>left : string
37+
>length : number
38+
39+
a.other.length; // Error expected here
40+
>a.other.length : number
41+
>a.other : string | undefined
42+
>a : Alignments
43+
>other : string | undefined
44+
>length : number
45+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @strict: true
2+
// @noUncheckedIndexedAccess: true
3+
4+
// Repro from #50683
5+
6+
type Alignment = (string & {}) | "left" | "center" | "right";
7+
type Alignments = Record<Alignment, string>;
8+
9+
const a: Alignments = {
10+
left: "align-left",
11+
center: "align-center",
12+
right: "align-right",
13+
other: "align-other",
14+
};
15+
16+
a.left.length;
17+
a.other.length; // Error expected here

0 commit comments

Comments
 (0)