Skip to content

Commit bf6c809

Browse files
committed
feat: add typeof modifier in template string
1 parent 12eac68 commit bf6c809

File tree

4 files changed

+16
-5
lines changed

4 files changed

+16
-5
lines changed

src/compiler/checker.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13438,13 +13438,16 @@ namespace ts {
1343813438
let i = 0;
1343913439
while (i < types.length) {
1344013440
const t = types[i];
13441-
if (t.flags & TypeFlags.Literal) {
13442-
const s = applyTemplateCasing(getTemplateStringForType(t) || "", casings[i]);
13441+
const casingType = casings[i];
13442+
const isGeneric = isGenericIndexType(t);
13443+
const resolvable = (t.flags & TypeFlags.Literal) || (!isGeneric && casingType === TemplateCasing.TypeOf);
13444+
if (resolvable) {
13445+
const s = applyTemplateCasing(getTemplateStringForType(t, casingType) || "", casingType);
1344313446
texts = [...texts.slice(0, i), texts[i] + s + texts[i + 1], ...texts.slice(i + 2)];
1344413447
casings = [...casings.slice(0, i), ...casings.slice(i + 1)];
1344513448
types = [...types.slice(0, i), ...types.slice(i + 1)];
1344613449
}
13447-
else if (isGenericIndexType(t)) {
13450+
else if (isGeneric) {
1344813451
i++;
1344913452
}
1345013453
else {
@@ -13462,7 +13465,10 @@ namespace ts {
1346213465
return type;
1346313466
}
1346413467

13465-
function getTemplateStringForType(type: Type) {
13468+
function getTemplateStringForType(type: Type, casing: TemplateCasing) {
13469+
if (casing === TemplateCasing.TypeOf) {
13470+
return getTypeNameForErrorDisplay(type);
13471+
}
1346613472
return type.flags & TypeFlags.StringLiteral ? (<StringLiteralType>type).value :
1346713473
type.flags & TypeFlags.NumberLiteral ? "" + (<NumberLiteralType>type).value :
1346813474
type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((<BigIntLiteralType>type).value) :
@@ -31418,7 +31424,9 @@ namespace ts {
3141831424
getTypeFromTypeNode(node);
3141931425
for (const span of node.templateSpans) {
3142031426
const type = getTypeFromTypeNode(span.type);
31421-
checkTypeAssignableTo(type, templateConstraintType, span.type);
31427+
if (span.casing !== TemplateCasing.TypeOf) {
31428+
checkTypeAssignableTo(type, templateConstraintType, span.type);
31429+
}
3142231430
if (!everyType(type, t => !!(t.flags & TypeFlags.Literal) || isGenericIndexType(t))) {
3142331431
error(span.type, Diagnostics.Template_type_argument_0_is_not_literal_type_or_a_generic_type, typeToString(type));
3142431432
}

src/compiler/emitter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2013,6 +2013,7 @@ namespace ts {
20132013
node.casing === TemplateCasing.Lowercase ? "lowercase" :
20142014
node.casing === TemplateCasing.Capitalize ? "capitalize" :
20152015
node.casing === TemplateCasing.Uncapitalize ? "uncapitalize" :
2016+
node.casing === TemplateCasing.TypeOf ? "typeof" :
20162017
undefined;
20172018
if (keyword) {
20182019
writeKeyword(keyword);

src/compiler/parser.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ namespace ts {
26212621
parseOptional(SyntaxKind.LowercaseKeyword) ? TemplateCasing.Lowercase :
26222622
parseOptional(SyntaxKind.CapitalizeKeyword) ? TemplateCasing.Capitalize :
26232623
parseOptional(SyntaxKind.UncapitalizeKeyword) ? TemplateCasing.Uncapitalize :
2624+
parseOptional(SyntaxKind.TypeOfKeyword) ? TemplateCasing.TypeOf :
26242625
TemplateCasing.None;
26252626
}
26262627

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,6 +1672,7 @@ namespace ts {
16721672
Lowercase,
16731673
Capitalize,
16741674
Uncapitalize,
1675+
TypeOf,
16751676
}
16761677

16771678
// Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.

0 commit comments

Comments
 (0)