Skip to content

Commit bf0eef4

Browse files
authored
fix(48034): Get a literal string of type intersection in a template literal type (#48044)
1 parent 6cb58d3 commit bf0eef4

File tree

5 files changed

+218
-5
lines changed

5 files changed

+218
-5
lines changed

src/compiler/checker.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -15256,24 +15256,32 @@ namespace ts {
1525615256
}
1525715257
return type;
1525815258

15259-
function addSpans(texts: readonly string[], types: readonly Type[]): boolean {
15259+
function addSpans(texts: readonly string[] | string, types: readonly Type[]): boolean {
15260+
const isTextsArray = isArray(texts);
1526015261
for (let i = 0; i < types.length; i++) {
1526115262
const t = types[i];
15263+
const addText = isTextsArray ? texts[i + 1] : texts;
1526215264
if (t.flags & (TypeFlags.Literal | TypeFlags.Null | TypeFlags.Undefined)) {
1526315265
text += getTemplateStringForType(t) || "";
15264-
text += texts[i + 1];
15266+
text += addText;
15267+
if (!isTextsArray) return true;
1526515268
}
1526615269
else if (t.flags & TypeFlags.TemplateLiteral) {
1526715270
text += (t as TemplateLiteralType).texts[0];
1526815271
if (!addSpans((t as TemplateLiteralType).texts, (t as TemplateLiteralType).types)) return false;
15269-
text += texts[i + 1];
15272+
text += addText;
15273+
if (!isTextsArray) return true;
1527015274
}
1527115275
else if (isGenericIndexType(t) || isPatternLiteralPlaceholderType(t)) {
1527215276
newTypes.push(t);
1527315277
newTexts.push(text);
15274-
text = texts[i + 1];
15278+
text = addText;
1527515279
}
15276-
else {
15280+
else if (t.flags & TypeFlags.Intersection) {
15281+
const added = addSpans(texts[i + 1], (t as IntersectionType).types);
15282+
if (!added) return false;
15283+
}
15284+
else if (isTextsArray) {
1527715285
return false;
1527815286
}
1527915287
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//// [templateLiteralIntersection.ts]
2+
// https://github.com/microsoft/TypeScript/issues/48034
3+
const a = 'a'
4+
5+
type A = typeof a
6+
type MixA = A & {foo: string}
7+
8+
type OriginA1 = `${A}`
9+
type OriginA2 = `${MixA}`
10+
11+
type B = `${typeof a}`
12+
type MixB = B & { foo: string }
13+
14+
type OriginB1 = `${B}`
15+
type OriginB2 = `${MixB}`
16+
17+
type MixC = { foo: string } & A
18+
19+
type OriginC = `${MixC}`
20+
21+
type MixD<T extends string> =
22+
`${T & { foo: string }}`
23+
type OriginD = `${MixD<A & { foo: string }> & { foo: string }}`;
24+
25+
type E = `${A & {}}`;
26+
type MixE = E & {}
27+
type OriginE = `${MixE}`
28+
29+
type OriginF = `${A}foo${A}`;
30+
31+
//// [templateLiteralIntersection.js]
32+
// https://github.com/microsoft/TypeScript/issues/48034
33+
var a = 'a';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
=== tests/cases/compiler/templateLiteralIntersection.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/48034
3+
const a = 'a'
4+
>a : Symbol(a, Decl(templateLiteralIntersection.ts, 1, 5))
5+
6+
type A = typeof a
7+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
8+
>a : Symbol(a, Decl(templateLiteralIntersection.ts, 1, 5))
9+
10+
type MixA = A & {foo: string}
11+
>MixA : Symbol(MixA, Decl(templateLiteralIntersection.ts, 3, 17))
12+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
13+
>foo : Symbol(foo, Decl(templateLiteralIntersection.ts, 4, 17))
14+
15+
type OriginA1 = `${A}`
16+
>OriginA1 : Symbol(OriginA1, Decl(templateLiteralIntersection.ts, 4, 29))
17+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
18+
19+
type OriginA2 = `${MixA}`
20+
>OriginA2 : Symbol(OriginA2, Decl(templateLiteralIntersection.ts, 6, 22))
21+
>MixA : Symbol(MixA, Decl(templateLiteralIntersection.ts, 3, 17))
22+
23+
type B = `${typeof a}`
24+
>B : Symbol(B, Decl(templateLiteralIntersection.ts, 7, 25))
25+
>a : Symbol(a, Decl(templateLiteralIntersection.ts, 1, 5))
26+
27+
type MixB = B & { foo: string }
28+
>MixB : Symbol(MixB, Decl(templateLiteralIntersection.ts, 9, 22))
29+
>B : Symbol(B, Decl(templateLiteralIntersection.ts, 7, 25))
30+
>foo : Symbol(foo, Decl(templateLiteralIntersection.ts, 10, 17))
31+
32+
type OriginB1 = `${B}`
33+
>OriginB1 : Symbol(OriginB1, Decl(templateLiteralIntersection.ts, 10, 31))
34+
>B : Symbol(B, Decl(templateLiteralIntersection.ts, 7, 25))
35+
36+
type OriginB2 = `${MixB}`
37+
>OriginB2 : Symbol(OriginB2, Decl(templateLiteralIntersection.ts, 12, 22))
38+
>MixB : Symbol(MixB, Decl(templateLiteralIntersection.ts, 9, 22))
39+
40+
type MixC = { foo: string } & A
41+
>MixC : Symbol(MixC, Decl(templateLiteralIntersection.ts, 13, 25))
42+
>foo : Symbol(foo, Decl(templateLiteralIntersection.ts, 15, 13))
43+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
44+
45+
type OriginC = `${MixC}`
46+
>OriginC : Symbol(OriginC, Decl(templateLiteralIntersection.ts, 15, 31))
47+
>MixC : Symbol(MixC, Decl(templateLiteralIntersection.ts, 13, 25))
48+
49+
type MixD<T extends string> =
50+
>MixD : Symbol(MixD, Decl(templateLiteralIntersection.ts, 17, 24))
51+
>T : Symbol(T, Decl(templateLiteralIntersection.ts, 19, 10))
52+
53+
`${T & { foo: string }}`
54+
>T : Symbol(T, Decl(templateLiteralIntersection.ts, 19, 10))
55+
>foo : Symbol(foo, Decl(templateLiteralIntersection.ts, 20, 12))
56+
57+
type OriginD = `${MixD<A & { foo: string }> & { foo: string }}`;
58+
>OriginD : Symbol(OriginD, Decl(templateLiteralIntersection.ts, 20, 28))
59+
>MixD : Symbol(MixD, Decl(templateLiteralIntersection.ts, 17, 24))
60+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
61+
>foo : Symbol(foo, Decl(templateLiteralIntersection.ts, 21, 28))
62+
>foo : Symbol(foo, Decl(templateLiteralIntersection.ts, 21, 47))
63+
64+
type E = `${A & {}}`;
65+
>E : Symbol(E, Decl(templateLiteralIntersection.ts, 21, 64))
66+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
67+
68+
type MixE = E & {}
69+
>MixE : Symbol(MixE, Decl(templateLiteralIntersection.ts, 23, 21))
70+
>E : Symbol(E, Decl(templateLiteralIntersection.ts, 21, 64))
71+
72+
type OriginE = `${MixE}`
73+
>OriginE : Symbol(OriginE, Decl(templateLiteralIntersection.ts, 24, 18))
74+
>MixE : Symbol(MixE, Decl(templateLiteralIntersection.ts, 23, 21))
75+
76+
type OriginF = `${A}foo${A}`;
77+
>OriginF : Symbol(OriginF, Decl(templateLiteralIntersection.ts, 25, 24))
78+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
79+
>A : Symbol(A, Decl(templateLiteralIntersection.ts, 1, 13))
80+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
=== tests/cases/compiler/templateLiteralIntersection.ts ===
2+
// https://github.com/microsoft/TypeScript/issues/48034
3+
const a = 'a'
4+
>a : "a"
5+
>'a' : "a"
6+
7+
type A = typeof a
8+
>A : "a"
9+
>a : "a"
10+
11+
type MixA = A & {foo: string}
12+
>MixA : MixA
13+
>foo : string
14+
15+
type OriginA1 = `${A}`
16+
>OriginA1 : "a"
17+
18+
type OriginA2 = `${MixA}`
19+
>OriginA2 : "a"
20+
21+
type B = `${typeof a}`
22+
>B : "a"
23+
>a : "a"
24+
25+
type MixB = B & { foo: string }
26+
>MixB : MixB
27+
>foo : string
28+
29+
type OriginB1 = `${B}`
30+
>OriginB1 : "a"
31+
32+
type OriginB2 = `${MixB}`
33+
>OriginB2 : "a"
34+
35+
type MixC = { foo: string } & A
36+
>MixC : MixC
37+
>foo : string
38+
39+
type OriginC = `${MixC}`
40+
>OriginC : "a"
41+
42+
type MixD<T extends string> =
43+
>MixD : `${T & { foo: string; }}`
44+
45+
`${T & { foo: string }}`
46+
>foo : string
47+
48+
type OriginD = `${MixD<A & { foo: string }> & { foo: string }}`;
49+
>OriginD : "a"
50+
>foo : string
51+
>foo : string
52+
53+
type E = `${A & {}}`;
54+
>E : "a"
55+
56+
type MixE = E & {}
57+
>MixE : MixE
58+
59+
type OriginE = `${MixE}`
60+
>OriginE : "a"
61+
62+
type OriginF = `${A}foo${A}`;
63+
>OriginF : "afooa"
64+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// https://github.com/microsoft/TypeScript/issues/48034
2+
const a = 'a'
3+
4+
type A = typeof a
5+
type MixA = A & {foo: string}
6+
7+
type OriginA1 = `${A}`
8+
type OriginA2 = `${MixA}`
9+
10+
type B = `${typeof a}`
11+
type MixB = B & { foo: string }
12+
13+
type OriginB1 = `${B}`
14+
type OriginB2 = `${MixB}`
15+
16+
type MixC = { foo: string } & A
17+
18+
type OriginC = `${MixC}`
19+
20+
type MixD<T extends string> =
21+
`${T & { foo: string }}`
22+
type OriginD = `${MixD<A & { foo: string }> & { foo: string }}`;
23+
24+
type E = `${A & {}}`;
25+
type MixE = E & {}
26+
type OriginE = `${MixE}`
27+
28+
type OriginF = `${A}foo${A}`;

0 commit comments

Comments
 (0)