Initial implementation of 'keyof T' type operator

This commit is contained in:
Anders Hejlsberg
2016-10-24 15:24:26 -07:00
parent 39a4feb90a
commit ad88109420
8 changed files with 71 additions and 3 deletions
+1
View File
@@ -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
View File
@@ -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:
+8
View File
@@ -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) {
+8
View File
@@ -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
View File
@@ -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 {
+1
View File
@@ -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,
+2
View File
@@ -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:
+8
View File
@@ -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;