From 198754fe7be4068952af9646543e068067126b11 Mon Sep 17 00:00:00 2001 From: Jack Works Date: Sun, 6 Sep 2020 16:59:01 +0800 Subject: [PATCH] feat: add typeof modifier in template string --- src/compiler/checker.ts | 18 +++++++++++++----- src/compiler/emitter.ts | 1 + src/compiler/parser.ts | 1 + src/compiler/types.ts | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2dbbcb653ce4e..ffeaf8fc758f5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13439,12 +13439,15 @@ namespace ts { let text = texts[0]; for (let i = 0; i < types.length; i++) { const t = types[i]; - if (t.flags & TypeFlags.Literal) { - const s = applyTemplateCasing(getTemplateStringForType(t) || "", casings[i]); + const casingType = casings[i]; + const isGeneric = isGenericIndexType(t); + const resolvable = (t.flags & TypeFlags.Literal) || (!isGeneric && casingType === TemplateCasing.TypeOf); + if (resolvable) { + const s = applyTemplateCasing(getTemplateStringForType(t, casingType) || "", casingType); text += s; text += texts[i + 1]; } - else if (isGenericIndexType(t)) { + else if (isGeneric) { newTypes.push(t); newCasings.push(casings[i]); newTexts.push(text); @@ -13466,7 +13469,10 @@ namespace ts { return type; } - function getTemplateStringForType(type: Type) { + function getTemplateStringForType(type: Type, casing: TemplateCasing) { + if (casing === TemplateCasing.TypeOf) { + return getTypeNameForErrorDisplay(type); + } return type.flags & TypeFlags.StringLiteral ? (type).value : type.flags & TypeFlags.NumberLiteral ? "" + (type).value : type.flags & TypeFlags.BigIntLiteral ? pseudoBigIntToString((type).value) : @@ -31424,7 +31430,9 @@ namespace ts { getTypeFromTypeNode(node); for (const span of node.templateSpans) { const type = getTypeFromTypeNode(span.type); - checkTypeAssignableTo(type, templateConstraintType, span.type); + if (span.casing !== TemplateCasing.TypeOf) { + checkTypeAssignableTo(type, templateConstraintType, span.type); + } if (!everyType(type, t => !!(t.flags & TypeFlags.Literal) || isGenericIndexType(t))) { error(span.type, Diagnostics.Template_type_argument_0_is_not_literal_type_or_a_generic_type, typeToString(type)); } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 1255ad200fbb8..5627697e34b70 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -2013,6 +2013,7 @@ namespace ts { node.casing === TemplateCasing.Lowercase ? "lowercase" : node.casing === TemplateCasing.Capitalize ? "capitalize" : node.casing === TemplateCasing.Uncapitalize ? "uncapitalize" : + node.casing === TemplateCasing.TypeOf ? "typeof" : undefined; if (keyword) { writeKeyword(keyword); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index bca7d0ed7a19c..44bc0ec33ac22 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2621,6 +2621,7 @@ namespace ts { parseOptional(SyntaxKind.LowercaseKeyword) ? TemplateCasing.Lowercase : parseOptional(SyntaxKind.CapitalizeKeyword) ? TemplateCasing.Capitalize : parseOptional(SyntaxKind.UncapitalizeKeyword) ? TemplateCasing.Uncapitalize : + parseOptional(SyntaxKind.TypeOfKeyword) ? TemplateCasing.TypeOf : TemplateCasing.None; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 14cc36c5a0ce7..6dbaedf36f8b2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1672,6 +1672,7 @@ namespace ts { Lowercase, Capitalize, Uncapitalize, + TypeOf, } // Note: 'brands' in our syntax nodes serve to give us a small amount of nominal typing.