Skip to content

Commit 0277fbb

Browse files
committed
Treat primitive and object Intersection Type inside TemplateLiteral as primitive
1 parent 34ea32f commit 0277fbb

File tree

7 files changed

+267
-0
lines changed

7 files changed

+267
-0
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22913,6 +22913,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2291322913
}
2291422914
}
2291522915

22916+
if (source.flags & TypeFlags.TemplateLiteral) {
22917+
if (target.flags & TypeFlags.StringLike) {
22918+
const resolvedPrimitiveTypes = (source as TemplateLiteralType).types.flatMap(type => {
22919+
if (type.flags & TypeFlags.Intersection && (type as IntersectionType).types.every(type => type.flags & TypeFlags.Primitive || type.flags & TypeFlags.Object)) {
22920+
return (type as IntersectionType).types.filter(t => t.flags & TypeFlags.Primitive);
22921+
} else {
22922+
return [type];
22923+
}
22924+
});
22925+
22926+
(source as TemplateLiteralType).types = resolvedPrimitiveTypes;
22927+
}
22928+
}
22929+
2291622930
// We limit alias variance probing to only object and conditional types since their alias behavior
2291722931
// is more predictable than other, interned types, which may or may not have an alias depending on
2291822932
// the order in which things were checked.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [tests/cases/compiler/brandedLiteralRevert1.ts] ////
2+
3+
=== brandedLiteralRevert1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/60990
5+
6+
type N0 = number & {
7+
>N0 : Symbol(N0, Decl(brandedLiteralRevert1.ts, 0, 0))
8+
9+
test: "TEST"
10+
>test : Symbol(test, Decl(brandedLiteralRevert1.ts, 2, 20))
11+
}
12+
13+
type N1 = 3 & {
14+
>N1 : Symbol(N1, Decl(brandedLiteralRevert1.ts, 4, 1))
15+
16+
test: "TEST"
17+
>test : Symbol(test, Decl(brandedLiteralRevert1.ts, 6, 15))
18+
}
19+
20+
declare let n0: N0
21+
>n0 : Symbol(n0, Decl(brandedLiteralRevert1.ts, 10, 11))
22+
>N0 : Symbol(N0, Decl(brandedLiteralRevert1.ts, 0, 0))
23+
24+
declare let n1: N1
25+
>n1 : Symbol(n1, Decl(brandedLiteralRevert1.ts, 11, 11))
26+
>N1 : Symbol(N1, Decl(brandedLiteralRevert1.ts, 4, 1))
27+
28+
let m0: `${number}` = `${n0}` // ok
29+
>m0 : Symbol(m0, Decl(brandedLiteralRevert1.ts, 13, 3))
30+
>n0 : Symbol(n0, Decl(brandedLiteralRevert1.ts, 10, 11))
31+
32+
let m1: "3" = `${n1}` // ok
33+
>m1 : Symbol(m1, Decl(brandedLiteralRevert1.ts, 14, 3))
34+
>n1 : Symbol(n1, Decl(brandedLiteralRevert1.ts, 11, 11))
35+
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//// [tests/cases/compiler/brandedLiteralRevert1.ts] ////
2+
3+
=== brandedLiteralRevert1.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/60990
5+
6+
type N0 = number & {
7+
>N0 : N0
8+
> : ^^
9+
10+
test: "TEST"
11+
>test : "TEST"
12+
> : ^^^^^^
13+
}
14+
15+
type N1 = 3 & {
16+
>N1 : N1
17+
> : ^^
18+
19+
test: "TEST"
20+
>test : "TEST"
21+
> : ^^^^^^
22+
}
23+
24+
declare let n0: N0
25+
>n0 : N0
26+
> : ^^
27+
28+
declare let n1: N1
29+
>n1 : N1
30+
> : ^^
31+
32+
let m0: `${number}` = `${n0}` // ok
33+
>m0 : `${number}`
34+
> : ^^^^^^^^^^^
35+
>`${n0}` : `${number}`
36+
> : ^^^^^^^^^^^
37+
>n0 : N0
38+
> : ^^
39+
40+
let m1: "3" = `${n1}` // ok
41+
>m1 : "3"
42+
> : ^^^
43+
>`${n1}` : `${3}`
44+
> : ^^^^^^
45+
>n1 : N1
46+
> : ^^
47+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//// [tests/cases/compiler/brandedLiteralRevert2.ts] ////
2+
3+
=== brandedLiteralRevert2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/60990
5+
6+
type Brand1 = number & 1 & {
7+
>Brand1 : Symbol(Brand1, Decl(brandedLiteralRevert2.ts, 0, 0))
8+
9+
test: "TEST"
10+
>test : Symbol(test, Decl(brandedLiteralRevert2.ts, 2, 28))
11+
}
12+
13+
type Brand2 = "a" & {
14+
>Brand2 : Symbol(Brand2, Decl(brandedLiteralRevert2.ts, 4, 1))
15+
16+
test: "TEST1"
17+
>test : Symbol(test, Decl(brandedLiteralRevert2.ts, 6, 21))
18+
}
19+
20+
let brandN1: Brand1 = 1 as Brand1
21+
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
22+
>Brand1 : Symbol(Brand1, Decl(brandedLiteralRevert2.ts, 0, 0))
23+
>Brand1 : Symbol(Brand1, Decl(brandedLiteralRevert2.ts, 0, 0))
24+
25+
let brandN2: Brand2 = "a" as Brand2
26+
>brandN2 : Symbol(brandN2, Decl(brandedLiteralRevert2.ts, 11, 3))
27+
>Brand2 : Symbol(Brand2, Decl(brandedLiteralRevert2.ts, 4, 1))
28+
>Brand2 : Symbol(Brand2, Decl(brandedLiteralRevert2.ts, 4, 1))
29+
30+
let brandM11: `${number}` = `${brandN1}` // ok
31+
>brandM11 : Symbol(brandM11, Decl(brandedLiteralRevert2.ts, 13, 3))
32+
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
33+
34+
let brandM12: "1" = `${brandN1}` // ok
35+
>brandM12 : Symbol(brandM12, Decl(brandedLiteralRevert2.ts, 14, 3))
36+
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
37+
38+
let brandM13: `${1}` = `${brandN1}` // ok
39+
>brandM13 : Symbol(brandM13, Decl(brandedLiteralRevert2.ts, 15, 3))
40+
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
41+
42+
let brandM21: "a" = `${brandN2}` // ok
43+
>brandM21 : Symbol(brandM21, Decl(brandedLiteralRevert2.ts, 17, 3))
44+
>brandN2 : Symbol(brandN2, Decl(brandedLiteralRevert2.ts, 11, 3))
45+
46+
let brandM22: "1a" = `${brandN1}${brandN2}` // ok
47+
>brandM22 : Symbol(brandM22, Decl(brandedLiteralRevert2.ts, 18, 3))
48+
>brandN1 : Symbol(brandN1, Decl(brandedLiteralRevert2.ts, 10, 3))
49+
>brandN2 : Symbol(brandN2, Decl(brandedLiteralRevert2.ts, 11, 3))
50+
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//// [tests/cases/compiler/brandedLiteralRevert2.ts] ////
2+
3+
=== brandedLiteralRevert2.ts ===
4+
// https://github.com/microsoft/TypeScript/issues/60990
5+
6+
type Brand1 = number & 1 & {
7+
>Brand1 : Brand1
8+
> : ^^^^^^
9+
10+
test: "TEST"
11+
>test : "TEST"
12+
> : ^^^^^^
13+
}
14+
15+
type Brand2 = "a" & {
16+
>Brand2 : Brand2
17+
> : ^^^^^^
18+
19+
test: "TEST1"
20+
>test : "TEST1"
21+
> : ^^^^^^^
22+
}
23+
24+
let brandN1: Brand1 = 1 as Brand1
25+
>brandN1 : Brand1
26+
> : ^^^^^^
27+
>1 as Brand1 : Brand1
28+
> : ^^^^^^
29+
>1 : 1
30+
> : ^
31+
32+
let brandN2: Brand2 = "a" as Brand2
33+
>brandN2 : Brand2
34+
> : ^^^^^^
35+
>"a" as Brand2 : Brand2
36+
> : ^^^^^^
37+
>"a" : "a"
38+
> : ^^^
39+
40+
let brandM11: `${number}` = `${brandN1}` // ok
41+
>brandM11 : `${number}`
42+
> : ^^^^^^^^^^^
43+
>`${brandN1}` : `${1}`
44+
> : ^^^^^^
45+
>brandN1 : Brand1
46+
> : ^^^^^^
47+
48+
let brandM12: "1" = `${brandN1}` // ok
49+
>brandM12 : "1"
50+
> : ^^^
51+
>`${brandN1}` : `${1}`
52+
> : ^^^^^^
53+
>brandN1 : Brand1
54+
> : ^^^^^^
55+
56+
let brandM13: `${1}` = `${brandN1}` // ok
57+
>brandM13 : "1"
58+
> : ^^^
59+
>`${brandN1}` : `${1}`
60+
> : ^^^^^^
61+
>brandN1 : Brand1
62+
> : ^^^^^^
63+
64+
let brandM21: "a" = `${brandN2}` // ok
65+
>brandM21 : "a"
66+
> : ^^^
67+
>`${brandN2}` : `${"a"}`
68+
> : ^^^^^^^^
69+
>brandN2 : Brand2
70+
> : ^^^^^^
71+
72+
let brandM22: "1a" = `${brandN1}${brandN2}` // ok
73+
>brandM22 : "1a"
74+
> : ^^^^
75+
>`${brandN1}${brandN2}` : `${1}${"a"}`
76+
> : ^^^^^^^^^^^^
77+
>brandN1 : Brand1
78+
> : ^^^^^^
79+
>brandN2 : Brand2
80+
> : ^^^^^^
81+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/60990
5+
6+
type N0 = number & {
7+
test: "TEST"
8+
}
9+
10+
type N1 = 3 & {
11+
test: "TEST"
12+
}
13+
14+
declare let n0: N0
15+
declare let n1: N1
16+
17+
let m0: `${number}` = `${n0}` // ok
18+
let m1: "3" = `${n1}` // ok
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @strict: true
2+
// @noEmit: true
3+
4+
// https://github.com/microsoft/TypeScript/issues/60990
5+
6+
type Brand1 = number & 1 & {
7+
test: "TEST"
8+
}
9+
10+
type Brand2 = "a" & {
11+
test: "TEST1"
12+
}
13+
14+
let brandN1: Brand1 = 1 as Brand1
15+
let brandN2: Brand2 = "a" as Brand2
16+
17+
let brandM11: `${number}` = `${brandN1}` // ok
18+
let brandM12: "1" = `${brandN1}` // ok
19+
let brandM13: `${1}` = `${brandN1}` // ok
20+
21+
let brandM21: "a" = `${brandN2}` // ok
22+
let brandM22: "1a" = `${brandN1}${brandN2}` // ok

0 commit comments

Comments
 (0)