mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-25 16:07:52 -05:00
Template literal types and mapped type 'as' clauses (#40336)
* Initial implementation of string template types
* Accept new API baselines
* Accept new baselines
* Unified checking for large cross product union types
* Accept new baselines
* Ensure errors from union type resolution are reported
* Accept new baselines
* Compute constraints for string template types
* Support `as T` clause in mapped types
* Accept new API baselines
* Add missing semicolon
* Add checking of `as T` clauses
* Support casing modifiers in string template types
* Accept new baselines
* Bump keyword maximum length
* fix anders
* Revert "fix anders"
This reverts commit b3178d4618.
* Properly handle 'as T' clause with keyof for mapped type
* Fix lint error
* Single character inferences and anchored end span matching
* Fewer array copy operations in template literal type resolution
* Handle cases where 'as T' maps multiple properties onto one
* Fix lint error
* Store key type instead of type mapper in MappedSymbol
* No constraint on `in T` type when `as N` clause present
* Rename from TemplateType to TemplateLiteralType
* Accept new API baselines
* Add tests
* Accept new baselines
* Address CR feedback
* Accept new API baselines
Co-authored-by: Erich Gamma <egamma@microsoft.com>
This commit is contained in:
@@ -206,6 +206,7 @@ namespace ts {
|
||||
case SyntaxKind.MappedType:
|
||||
return visitNode(cbNode, (<MappedTypeNode>node).readonlyToken) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).typeParameter) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).nameType) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).questionToken) ||
|
||||
visitNode(cbNode, (<MappedTypeNode>node).type);
|
||||
case SyntaxKind.LiteralType:
|
||||
@@ -424,6 +425,10 @@ namespace ts {
|
||||
return visitNode(cbNode, (<TemplateExpression>node).head) || visitNodes(cbNode, cbNodes, (<TemplateExpression>node).templateSpans);
|
||||
case SyntaxKind.TemplateSpan:
|
||||
return visitNode(cbNode, (<TemplateSpan>node).expression) || visitNode(cbNode, (<TemplateSpan>node).literal);
|
||||
case SyntaxKind.TemplateLiteralType:
|
||||
return visitNode(cbNode, (<TemplateLiteralTypeNode>node).head) || visitNodes(cbNode, cbNodes, (<TemplateLiteralTypeNode>node).templateSpans);
|
||||
case SyntaxKind.TemplateLiteralTypeSpan:
|
||||
return visitNode(cbNode, (<TemplateLiteralTypeSpan>node).type) || visitNode(cbNode, (<TemplateLiteralTypeSpan>node).literal);
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return visitNode(cbNode, (<ComputedPropertyName>node).expression);
|
||||
case SyntaxKind.HeritageClause:
|
||||
@@ -2584,6 +2589,49 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
function parseTemplateType(): TemplateLiteralTypeNode {
|
||||
const pos = getNodePos();
|
||||
return finishNode(
|
||||
factory.createTemplateLiteralType(
|
||||
parseTemplateHead(/*isTaggedTemplate*/ false),
|
||||
parseTemplateTypeSpans()
|
||||
),
|
||||
pos
|
||||
);
|
||||
}
|
||||
|
||||
function parseTemplateTypeSpans() {
|
||||
const pos = getNodePos();
|
||||
const list = [];
|
||||
let node: TemplateLiteralTypeSpan;
|
||||
do {
|
||||
node = parseTemplateTypeSpan();
|
||||
list.push(node);
|
||||
}
|
||||
while (node.literal.kind === SyntaxKind.TemplateMiddle);
|
||||
return createNodeArray(list, pos);
|
||||
}
|
||||
|
||||
function parseTemplateTypeSpan(): TemplateLiteralTypeSpan {
|
||||
const pos = getNodePos();
|
||||
return finishNode(
|
||||
factory.createTemplateLiteralTypeSpan(
|
||||
parseTemplateCasing(),
|
||||
parseType(),
|
||||
parseLiteralOfTemplateSpan(/*isTaggedTemplate*/ false)
|
||||
),
|
||||
pos
|
||||
);
|
||||
}
|
||||
|
||||
function parseTemplateCasing(): TemplateCasing {
|
||||
return parseOptional(SyntaxKind.UppercaseKeyword) ? TemplateCasing.Uppercase :
|
||||
parseOptional(SyntaxKind.LowercaseKeyword) ? TemplateCasing.Lowercase :
|
||||
parseOptional(SyntaxKind.CapitalizeKeyword) ? TemplateCasing.Capitalize :
|
||||
parseOptional(SyntaxKind.UncapitalizeKeyword) ? TemplateCasing.Uncapitalize :
|
||||
TemplateCasing.None;
|
||||
}
|
||||
|
||||
function parseLiteralOfTemplateSpan(isTaggedTemplate: boolean) {
|
||||
if (token() === SyntaxKind.CloseBraceToken) {
|
||||
reScanTemplateToken(isTaggedTemplate);
|
||||
@@ -3252,6 +3300,7 @@ namespace ts {
|
||||
}
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
const typeParameter = parseMappedTypeParameter();
|
||||
const nameType = parseOptional(SyntaxKind.AsKeyword) ? parseType() : undefined;
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
let questionToken: QuestionToken | PlusToken | MinusToken | undefined;
|
||||
if (token() === SyntaxKind.QuestionToken || token() === SyntaxKind.PlusToken || token() === SyntaxKind.MinusToken) {
|
||||
@@ -3263,7 +3312,7 @@ namespace ts {
|
||||
const type = parseTypeAnnotation();
|
||||
parseSemicolon();
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), pos);
|
||||
return finishNode(factory.createMappedTypeNode(readonlyToken, typeParameter, nameType, questionToken, type), pos);
|
||||
}
|
||||
|
||||
function parseTupleElementType() {
|
||||
@@ -3444,6 +3493,8 @@ namespace ts {
|
||||
return parseImportType();
|
||||
case SyntaxKind.AssertsKeyword:
|
||||
return lookAhead(nextTokenIsIdentifierOrKeywordOnSameLine) ? parseAssertsTypePredicate() : parseTypeReference();
|
||||
case SyntaxKind.TemplateHead:
|
||||
return parseTemplateType();
|
||||
default:
|
||||
return parseTypeReference();
|
||||
}
|
||||
@@ -3485,6 +3536,8 @@ namespace ts {
|
||||
case SyntaxKind.InferKeyword:
|
||||
case SyntaxKind.ImportKeyword:
|
||||
case SyntaxKind.AssertsKeyword:
|
||||
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
||||
case SyntaxKind.TemplateHead:
|
||||
return true;
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
return !inStartOfParameter;
|
||||
|
||||
Reference in New Issue
Block a user