Skip to content

Type aliases #957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Oct 28, 2014
2,957 changes: 1,646 additions & 1,311 deletions bin/tsc.js

Large diffs are not rendered by default.

5,066 changes: 2,441 additions & 2,625 deletions bin/typescriptServices.js

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ module ts {
case SyntaxKind.InterfaceDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.TypeAliasDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.EnumDeclaration:
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes, /*isBlockScopeContainer*/ false);
break;
Expand Down
69 changes: 60 additions & 9 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ module ts {
emitFiles: invokeEmitter,
getParentOfSymbol: getParentOfSymbol,
getTypeOfSymbol: getTypeOfSymbol,
getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
getPropertiesOfType: getPropertiesOfType,
getPropertyOfType: getPropertyOfType,
getSignaturesOfType: getSignaturesOfType,
Expand Down Expand Up @@ -191,6 +192,7 @@ module ts {
if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes;
if (flags & SymbolFlags.SetAccessor) result |= SymbolFlags.SetAccessorExcludes;
if (flags & SymbolFlags.TypeParameter) result |= SymbolFlags.TypeParameterExcludes;
if (flags & SymbolFlags.TypeAlias) result |= SymbolFlags.TypeAliasExcludes;
if (flags & SymbolFlags.Import) result |= SymbolFlags.ImportExcludes;
return result;
}
Expand Down Expand Up @@ -479,7 +481,7 @@ module ts {
// import a = |b.c|; // Value, type, namespace
// import a = |b.c|.d; // Namespace
if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
entityName = entityName.parent;
entityName = <QualifiedName>entityName.parent;
}
// Check for case 1 and 3 in the above example
if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) {
Expand Down Expand Up @@ -1022,6 +1024,19 @@ module ts {
return result;
}

function getTypeAliasForTypeLiteral(type: Type): Symbol {
if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
var node = type.symbol.declarations[0].parent;
while (node.kind === SyntaxKind.ParenType) {
node = node.parent;
}
if (node.kind === SyntaxKind.TypeAliasDeclaration) {
return getSymbolOfNode(node);
}
}
return undefined;
}

// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
var _displayBuilder: SymbolDisplayBuilder;
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
Expand Down Expand Up @@ -1212,8 +1227,15 @@ module ts {
writeTypeofSymbol(type);
}
else if (typeStack && contains(typeStack, type)) {
// Recursive usage, use any
writeKeyword(writer, SyntaxKind.AnyKeyword);
// If type is an anonymous type literal in a type alias declaration, use type alias name
var typeAlias = getTypeAliasForTypeLiteral(type);
if (typeAlias) {
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type);
}
else {
// Recursive usage, use any
writeKeyword(writer, SyntaxKind.AnyKeyword);
}
}
else {
if (!typeStack) {
Expand Down Expand Up @@ -1537,6 +1559,7 @@ module ts {
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ImportDeclaration:
Expand Down Expand Up @@ -1940,6 +1963,24 @@ module ts {
return <InterfaceType>links.declaredType;
}

function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type {
var links = getSymbolLinks(symbol);
if (!links.declaredType) {
links.declaredType = resolvingType;
var declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
var type = getTypeFromTypeNode(declaration.type);
if (links.declaredType === resolvingType) {
links.declaredType = type;
}
}
else if (links.declaredType === resolvingType) {
links.declaredType = unknownType;
var declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
}
return links.declaredType;
}

function getDeclaredTypeOfEnum(symbol: Symbol): Type {
var links = getSymbolLinks(symbol);
if (!links.declaredType) {
Expand Down Expand Up @@ -1979,6 +2020,9 @@ module ts {
if (symbol.flags & SymbolFlags.Interface) {
return getDeclaredTypeOfInterface(symbol);
}
if (symbol.flags & SymbolFlags.TypeAlias) {
return getDeclaredTypeOfTypeAlias(symbol);
}
if (symbol.flags & SymbolFlags.Enum) {
return getDeclaredTypeOfEnum(symbol);
}
Expand Down Expand Up @@ -7566,6 +7610,10 @@ module ts {
}
}

function checkTypeAliasDeclaration(node: TypeAliasDeclaration) {
checkSourceElement(node.type);
}

function getConstantValueForExpression(node: Expression): number {
var isNegative = false;
if (node.kind === SyntaxKind.PrefixOperator) {
Expand Down Expand Up @@ -7858,6 +7906,8 @@ module ts {
return checkClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.InterfaceDeclaration:
return checkInterfaceDeclaration(<InterfaceDeclaration>node);
case SyntaxKind.TypeAliasDeclaration:
return checkTypeAliasDeclaration(<TypeAliasDeclaration>node);
case SyntaxKind.EnumDeclaration:
return checkEnumDeclaration(<EnumDeclaration>node);
case SyntaxKind.ModuleDeclaration:
Expand Down Expand Up @@ -8102,6 +8152,7 @@ module ts {
case SyntaxKind.TypeParameter:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.EnumDeclaration:
return true;
}
Expand Down Expand Up @@ -8188,7 +8239,7 @@ module ts {

function isInRightSideOfImportOrExportAssignment(node: EntityName) {
while (node.parent.kind === SyntaxKind.QualifiedName) {
node = node.parent;
node = <QualifiedName>node.parent;
}

if (node.parent.kind === SyntaxKind.ImportDeclaration) {
Expand Down Expand Up @@ -8222,7 +8273,7 @@ module ts {
}

if (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
entityName = entityName.parent;
entityName = <QualifiedName>entityName.parent;
}

if (isExpression(entityName)) {
Expand All @@ -8235,7 +8286,7 @@ module ts {
else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccess) {
var symbol = getNodeLinks(entityName).resolvedSymbol;
if (!symbol) {
checkPropertyAccess(<PropertyAccess>entityName);
checkPropertyAccess(<QualifiedName>entityName);
}
return getNodeLinks(entityName).resolvedSymbol;
}
Expand Down Expand Up @@ -8267,10 +8318,10 @@ module ts {
return getSymbolOfNode(node.parent);
}

if (node.kind === SyntaxKind.Identifier && isInRightSideOfImportOrExportAssignment(node)) {
if (node.kind === SyntaxKind.Identifier && isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
return node.parent.kind === SyntaxKind.ExportAssignment
? getSymbolOfEntityName(<Identifier>node)
: getSymbolOfPartOfRightHandSideOfImport(node);
: getSymbolOfPartOfRightHandSideOfImport(<Identifier>node);
}

switch (node.kind) {
Expand Down Expand Up @@ -8351,7 +8402,7 @@ module ts {
return symbol && getTypeOfSymbol(symbol);
}

if (isInRightSideOfImportOrExportAssignment(node)) {
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
var symbol = getSymbolInfo(node);
var declaredType = symbol && getDeclaredTypeOfSymbol(symbol);
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);
Expand Down
7 changes: 4 additions & 3 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,10 @@ module ts {
break;
// If not a primitive, the possible types are specified in what is effectively a map of options.
default:
var value = (args[i++] || "").toLowerCase();
if (hasProperty(opt.type, value)) {
options[opt.name] = opt.type[value];
var map = <Map<number>>opt.type;
var key = (args[i++] || "").toLowerCase();
if (hasProperty(map, key)) {
options[opt.name] = map[key];
}
else {
errors.push(createCompilerDiagnostic(opt.error));
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/diagnosticInformationMap.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ module ts {
const_declarations_must_be_initialized: { code: 1155, category: DiagnosticCategory.Error, key: "'const' declarations must be initialized" },
const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." },
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
Aliased_type_cannot_be_an_object_type_literal_Use_an_interface_declaration_instead: { code: 1158, category: DiagnosticCategory.Error, key: "Aliased type cannot be an object type literal. Use an interface declaration instead." },
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
Expand Down Expand Up @@ -266,6 +267,7 @@ module ts {
An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." },
The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly: { code: 2453, category: DiagnosticCategory.Error, key: "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly." },
Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." },
Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Expand Down Expand Up @@ -345,6 +347,9 @@ module ts {
Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4076, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from external module {2} but cannot be named." },
Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2: { code: 4077, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using name '{1}' from private module '{2}'." },
Parameter_0_of_exported_function_has_or_is_using_private_name_1: { code: 4078, category: DiagnosticCategory.Error, key: "Parameter '{0}' of exported function has or is using private name '{1}'." },
Exported_type_alias_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named: { code: 4079, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using name '{1}' from external module {2} but cannot be named." },
Exported_type_alias_0_has_or_is_using_name_1_from_private_module_2: { code: 4080, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using name '{1}' from private module '{2}'." },
Exported_type_alias_0_has_or_is_using_private_name_1: { code: 4081, category: DiagnosticCategory.Error, key: "Exported type alias '{0}' has or is using private name '{1}'." },
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." },
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },
Expand Down
20 changes: 20 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@
"category": "Error",
"code": 1157
},
"Aliased type cannot be an object type literal. Use an interface declaration instead.": {
"category": "Error",
"code": 1158
},

"Duplicate identifier '{0}'.": {
"category": "Error",
Expand Down Expand Up @@ -1064,6 +1068,10 @@
"category": "Error",
"code": 2455
},
"Type alias '{0}' circularly references itself.": {
"category": "Error",
"code": 2456
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down Expand Up @@ -1381,6 +1389,18 @@
"category": "Error",
"code": 4078
},
"Exported type alias '{0}' has or is using name '{1}' from external module {2} but cannot be named.": {
"category": "Error",
"code": 4079
},
"Exported type alias '{0}' has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4080
},
"Exported type alias '{0}' has or is using private name '{1}'.": {
"category": "Error",
"code": 4081
},


"The current host does not support the '{0}' option.": {
Expand Down
28 changes: 28 additions & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2566,6 +2566,32 @@ module ts {
}
}

function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
emitDeclarationFlags(node);
write("type ");
emitSourceTextOfNode(node.name);
write(" = ");
getSymbolVisibilityDiagnosticMessage = getTypeAliasDeclarationVisibilityError;
resolver.writeTypeAtLocation(node.type, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
write(";");
writeLine();
}
function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
var diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_private_module_2 :
Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1;
return {
diagnosticMessage: diagnosticMessage,
errorNode: node,
typeName: node.name
};
}
}

function emitEnumDeclaration(node: EnumDeclaration) {
if (resolver.isDeclarationVisible(node)) {
emitJsDocComments(node);
Expand Down Expand Up @@ -3163,6 +3189,8 @@ module ts {
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
case SyntaxKind.ClassDeclaration:
return emitClassDeclaration(<ClassDeclaration>node);
case SyntaxKind.TypeAliasDeclaration:
return emitTypeAliasDeclaration(<TypeAliasDeclaration>node);
case SyntaxKind.EnumMember:
return emitEnumMemberDeclaration(<EnumMember>node);
case SyntaxKind.EnumDeclaration:
Expand Down
Loading