mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Initial implementation of 'keyof T' type operator
This commit is contained in:
@@ -3066,6 +3066,7 @@ namespace ts {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.LiteralType:
|
||||
// Types and signatures are TypeScript syntax, and exclude all other facts.
|
||||
transformFlags = TransformFlags.AssertTypeScript;
|
||||
|
||||
+24
-1
@@ -5663,6 +5663,26 @@ namespace ts {
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getLiteralTypeFromPropertyName(prop: Symbol) {
|
||||
return startsWith(prop.name, "__@") ? neverType : getLiteralTypeForText(TypeFlags.StringLiteral, unescapeIdentifier(prop.name));
|
||||
}
|
||||
|
||||
function getKeyOfType(type: Type): Type {
|
||||
if (getIndexInfoOfType(type, IndexKind.String)) {
|
||||
return getUnionType([stringType, numberType]);
|
||||
}
|
||||
const propKeysType = getUnionType(map(getPropertiesOfType(type), getLiteralTypeFromPropertyName));
|
||||
return getIndexInfoOfType(type, IndexKind.Number) ? getUnionType([numberType, propKeysType]) : propKeysType;
|
||||
}
|
||||
|
||||
function getTypeFromTypeOperatorNode(node: TypeOperatorNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getKeyOfType(getTypeFromTypeNodeNoAlias(node.type));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node, aliasSymbol?: Symbol, aliasTypeArguments?: Type[]): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
@@ -5822,6 +5842,8 @@ namespace ts {
|
||||
case SyntaxKind.JSDocTypeLiteral:
|
||||
case SyntaxKind.JSDocFunctionType:
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node, aliasSymbol, aliasTypeArguments);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
|
||||
// This function assumes that an identifier or qualified name is a type expression
|
||||
// Callers should first ensure this by calling isTypeNode
|
||||
case SyntaxKind.Identifier:
|
||||
@@ -18225,7 +18247,8 @@ namespace ts {
|
||||
case SyntaxKind.IntersectionType:
|
||||
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return checkSourceElement((<ParenthesizedTypeNode>node).type);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return checkFunctionDeclaration(<FunctionDeclaration>node);
|
||||
case SyntaxKind.Block:
|
||||
|
||||
@@ -413,6 +413,8 @@ namespace ts {
|
||||
return emitIntersectionType(<IntersectionTypeNode>type);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return emitParenType(<ParenthesizedTypeNode>type);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return emitTypeOperator(<TypeOperatorNode>type);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
return emitSignatureDeclarationWithJsDocComments(<FunctionOrConstructorTypeNode>type);
|
||||
@@ -506,6 +508,12 @@ namespace ts {
|
||||
write(")");
|
||||
}
|
||||
|
||||
function emitTypeOperator(type: TypeOperatorNode) {
|
||||
write(tokenToString(type.operator));
|
||||
write(" ");
|
||||
emitType(type.type);
|
||||
}
|
||||
|
||||
function emitTypeLiteral(type: TypeLiteralNode) {
|
||||
write("{");
|
||||
if (type.members.length) {
|
||||
|
||||
@@ -594,6 +594,8 @@ const _super = (function (geti, seti) {
|
||||
return emitExpressionWithTypeArguments(<ExpressionWithTypeArguments>node);
|
||||
case SyntaxKind.ThisType:
|
||||
return emitThisType();
|
||||
case SyntaxKind.TypeOperator:
|
||||
return emitTypeOperator(<TypeOperatorNode>node);
|
||||
case SyntaxKind.LiteralType:
|
||||
return emitLiteralType(<LiteralTypeNode>node);
|
||||
|
||||
@@ -1088,6 +1090,12 @@ const _super = (function (geti, seti) {
|
||||
write("this");
|
||||
}
|
||||
|
||||
function emitTypeOperator(node: TypeOperatorNode) {
|
||||
writeTokenText(node.operator);
|
||||
write(" ");
|
||||
emit(node.type);
|
||||
}
|
||||
|
||||
function emitLiteralType(node: LiteralTypeNode) {
|
||||
emitExpression(node.literal);
|
||||
}
|
||||
|
||||
+19
-2
@@ -134,7 +134,8 @@ namespace ts {
|
||||
case SyntaxKind.IntersectionType:
|
||||
return visitNodes(cbNodes, (<UnionOrIntersectionTypeNode>node).types);
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
return visitNode(cbNode, (<ParenthesizedTypeNode>node).type);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
case SyntaxKind.LiteralType:
|
||||
return visitNode(cbNode, (<LiteralTypeNode>node).literal);
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
@@ -2526,6 +2527,22 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) {
|
||||
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
|
||||
parseExpected(operator);
|
||||
node.operator = operator;
|
||||
node.type = parseTypeOperatorOrHigher();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseTypeOperatorOrHigher(): TypeNode {
|
||||
switch (token()) {
|
||||
case SyntaxKind.KeyOfKeyword:
|
||||
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
|
||||
}
|
||||
return parseArrayTypeOrHigher();
|
||||
}
|
||||
|
||||
function parseUnionOrIntersectionType(kind: SyntaxKind, parseConstituentType: () => TypeNode, operator: SyntaxKind): TypeNode {
|
||||
let type = parseConstituentType();
|
||||
if (token() === operator) {
|
||||
@@ -2542,7 +2559,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseIntersectionTypeOrHigher(): TypeNode {
|
||||
return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseArrayTypeOrHigher, SyntaxKind.AmpersandToken);
|
||||
return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseTypeOperatorOrHigher, SyntaxKind.AmpersandToken);
|
||||
}
|
||||
|
||||
function parseUnionTypeOrHigher(): TypeNode {
|
||||
|
||||
@@ -90,6 +90,7 @@ namespace ts {
|
||||
"instanceof": SyntaxKind.InstanceOfKeyword,
|
||||
"interface": SyntaxKind.InterfaceKeyword,
|
||||
"is": SyntaxKind.IsKeyword,
|
||||
"keyof": SyntaxKind.KeyOfKeyword,
|
||||
"let": SyntaxKind.LetKeyword,
|
||||
"module": SyntaxKind.ModuleKeyword,
|
||||
"namespace": SyntaxKind.NamespaceKeyword,
|
||||
|
||||
@@ -288,6 +288,7 @@ namespace ts {
|
||||
case SyntaxKind.IntersectionType:
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.ThisType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.LiteralType:
|
||||
// TypeScript type nodes are elided.
|
||||
|
||||
@@ -1856,6 +1857,7 @@ namespace ts {
|
||||
}
|
||||
// Fallthrough
|
||||
case SyntaxKind.TypeQuery:
|
||||
case SyntaxKind.TypeOperator:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.ThisType:
|
||||
|
||||
@@ -168,6 +168,7 @@ namespace ts {
|
||||
DeclareKeyword,
|
||||
GetKeyword,
|
||||
IsKeyword,
|
||||
KeyOfKeyword,
|
||||
ModuleKeyword,
|
||||
NamespaceKeyword,
|
||||
NeverKeyword,
|
||||
@@ -216,6 +217,7 @@ namespace ts {
|
||||
IntersectionType,
|
||||
ParenthesizedType,
|
||||
ThisType,
|
||||
TypeOperator,
|
||||
LiteralType,
|
||||
// Binding patterns
|
||||
ObjectBindingPattern,
|
||||
@@ -870,6 +872,12 @@ namespace ts {
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface TypeOperatorNode extends TypeNode {
|
||||
kind: SyntaxKind.TypeOperator;
|
||||
operator: SyntaxKind.KeyOfKeyword;
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface LiteralTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.LiteralType;
|
||||
literal: Expression;
|
||||
|
||||
Reference in New Issue
Block a user