Skip to content

Commit 16a79c5

Browse files
committed
Merge pull request #957 from Microsoft/typeAliases
Type aliases
2 parents 4ffd0b3 + 43ff75a commit 16a79c5

12 files changed

+4325
-4041
lines changed

bin/tsc.js

Lines changed: 1646 additions & 1311 deletions
Large diffs are not rendered by default.

bin/typescriptServices.js

Lines changed: 2441 additions & 2625 deletions
Large diffs are not rendered by default.

src/compiler/binder.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@ module ts {
360360
case SyntaxKind.InterfaceDeclaration:
361361
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes, /*isBlockScopeContainer*/ false);
362362
break;
363+
case SyntaxKind.TypeAliasDeclaration:
364+
bindDeclaration(<Declaration>node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes, /*isBlockScopeContainer*/ false);
365+
break;
363366
case SyntaxKind.EnumDeclaration:
364367
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes, /*isBlockScopeContainer*/ false);
365368
break;

src/compiler/checker.ts

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ module ts {
8686
emitFiles: invokeEmitter,
8787
getParentOfSymbol: getParentOfSymbol,
8888
getTypeOfSymbol: getTypeOfSymbol,
89+
getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
8990
getPropertiesOfType: getPropertiesOfType,
9091
getPropertyOfType: getPropertyOfType,
9192
getSignaturesOfType: getSignaturesOfType,
@@ -191,6 +192,7 @@ module ts {
191192
if (flags & SymbolFlags.GetAccessor) result |= SymbolFlags.GetAccessorExcludes;
192193
if (flags & SymbolFlags.SetAccessor) result |= SymbolFlags.SetAccessorExcludes;
193194
if (flags & SymbolFlags.TypeParameter) result |= SymbolFlags.TypeParameterExcludes;
195+
if (flags & SymbolFlags.TypeAlias) result |= SymbolFlags.TypeAliasExcludes;
194196
if (flags & SymbolFlags.Import) result |= SymbolFlags.ImportExcludes;
195197
return result;
196198
}
@@ -479,7 +481,7 @@ module ts {
479481
// import a = |b.c|; // Value, type, namespace
480482
// import a = |b.c|.d; // Namespace
481483
if (entityName.kind === SyntaxKind.Identifier && isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
482-
entityName = entityName.parent;
484+
entityName = <QualifiedName>entityName.parent;
483485
}
484486
// Check for case 1 and 3 in the above example
485487
if (entityName.kind === SyntaxKind.Identifier || entityName.parent.kind === SyntaxKind.QualifiedName) {
@@ -1022,6 +1024,19 @@ module ts {
10221024
return result;
10231025
}
10241026

1027+
function getTypeAliasForTypeLiteral(type: Type): Symbol {
1028+
if (type.symbol && type.symbol.flags & SymbolFlags.TypeLiteral) {
1029+
var node = type.symbol.declarations[0].parent;
1030+
while (node.kind === SyntaxKind.ParenType) {
1031+
node = node.parent;
1032+
}
1033+
if (node.kind === SyntaxKind.TypeAliasDeclaration) {
1034+
return getSymbolOfNode(node);
1035+
}
1036+
}
1037+
return undefined;
1038+
}
1039+
10251040
// This is for caching the result of getSymbolDisplayBuilder. Do not access directly.
10261041
var _displayBuilder: SymbolDisplayBuilder;
10271042
function getSymbolDisplayBuilder(): SymbolDisplayBuilder {
@@ -1212,8 +1227,15 @@ module ts {
12121227
writeTypeofSymbol(type);
12131228
}
12141229
else if (typeStack && contains(typeStack, type)) {
1215-
// Recursive usage, use any
1216-
writeKeyword(writer, SyntaxKind.AnyKeyword);
1230+
// If type is an anonymous type literal in a type alias declaration, use type alias name
1231+
var typeAlias = getTypeAliasForTypeLiteral(type);
1232+
if (typeAlias) {
1233+
buildSymbolDisplay(typeAlias, writer, enclosingDeclaration, SymbolFlags.Type);
1234+
}
1235+
else {
1236+
// Recursive usage, use any
1237+
writeKeyword(writer, SyntaxKind.AnyKeyword);
1238+
}
12171239
}
12181240
else {
12191241
if (!typeStack) {
@@ -1537,6 +1559,7 @@ module ts {
15371559
case SyntaxKind.ModuleDeclaration:
15381560
case SyntaxKind.ClassDeclaration:
15391561
case SyntaxKind.InterfaceDeclaration:
1562+
case SyntaxKind.TypeAliasDeclaration:
15401563
case SyntaxKind.FunctionDeclaration:
15411564
case SyntaxKind.EnumDeclaration:
15421565
case SyntaxKind.ImportDeclaration:
@@ -1940,6 +1963,24 @@ module ts {
19401963
return <InterfaceType>links.declaredType;
19411964
}
19421965

1966+
function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type {
1967+
var links = getSymbolLinks(symbol);
1968+
if (!links.declaredType) {
1969+
links.declaredType = resolvingType;
1970+
var declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
1971+
var type = getTypeFromTypeNode(declaration.type);
1972+
if (links.declaredType === resolvingType) {
1973+
links.declaredType = type;
1974+
}
1975+
}
1976+
else if (links.declaredType === resolvingType) {
1977+
links.declaredType = unknownType;
1978+
var declaration = <TypeAliasDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeAliasDeclaration);
1979+
error(declaration.name, Diagnostics.Type_alias_0_circularly_references_itself, symbolToString(symbol));
1980+
}
1981+
return links.declaredType;
1982+
}
1983+
19431984
function getDeclaredTypeOfEnum(symbol: Symbol): Type {
19441985
var links = getSymbolLinks(symbol);
19451986
if (!links.declaredType) {
@@ -1979,6 +2020,9 @@ module ts {
19792020
if (symbol.flags & SymbolFlags.Interface) {
19802021
return getDeclaredTypeOfInterface(symbol);
19812022
}
2023+
if (symbol.flags & SymbolFlags.TypeAlias) {
2024+
return getDeclaredTypeOfTypeAlias(symbol);
2025+
}
19822026
if (symbol.flags & SymbolFlags.Enum) {
19832027
return getDeclaredTypeOfEnum(symbol);
19842028
}
@@ -7566,6 +7610,10 @@ module ts {
75667610
}
75677611
}
75687612

7613+
function checkTypeAliasDeclaration(node: TypeAliasDeclaration) {
7614+
checkSourceElement(node.type);
7615+
}
7616+
75697617
function getConstantValueForExpression(node: Expression): number {
75707618
var isNegative = false;
75717619
if (node.kind === SyntaxKind.PrefixOperator) {
@@ -7858,6 +7906,8 @@ module ts {
78587906
return checkClassDeclaration(<ClassDeclaration>node);
78597907
case SyntaxKind.InterfaceDeclaration:
78607908
return checkInterfaceDeclaration(<InterfaceDeclaration>node);
7909+
case SyntaxKind.TypeAliasDeclaration:
7910+
return checkTypeAliasDeclaration(<TypeAliasDeclaration>node);
78617911
case SyntaxKind.EnumDeclaration:
78627912
return checkEnumDeclaration(<EnumDeclaration>node);
78637913
case SyntaxKind.ModuleDeclaration:
@@ -8102,6 +8152,7 @@ module ts {
81028152
case SyntaxKind.TypeParameter:
81038153
case SyntaxKind.ClassDeclaration:
81048154
case SyntaxKind.InterfaceDeclaration:
8155+
case SyntaxKind.TypeAliasDeclaration:
81058156
case SyntaxKind.EnumDeclaration:
81068157
return true;
81078158
}
@@ -8188,7 +8239,7 @@ module ts {
81888239

81898240
function isInRightSideOfImportOrExportAssignment(node: EntityName) {
81908241
while (node.parent.kind === SyntaxKind.QualifiedName) {
8191-
node = node.parent;
8242+
node = <QualifiedName>node.parent;
81928243
}
81938244

81948245
if (node.parent.kind === SyntaxKind.ImportDeclaration) {
@@ -8222,7 +8273,7 @@ module ts {
82228273
}
82238274

82248275
if (isRightSideOfQualifiedNameOrPropertyAccess(entityName)) {
8225-
entityName = entityName.parent;
8276+
entityName = <QualifiedName>entityName.parent;
82268277
}
82278278

82288279
if (isExpression(entityName)) {
@@ -8235,7 +8286,7 @@ module ts {
82358286
else if (entityName.kind === SyntaxKind.QualifiedName || entityName.kind === SyntaxKind.PropertyAccess) {
82368287
var symbol = getNodeLinks(entityName).resolvedSymbol;
82378288
if (!symbol) {
8238-
checkPropertyAccess(<PropertyAccess>entityName);
8289+
checkPropertyAccess(<QualifiedName>entityName);
82398290
}
82408291
return getNodeLinks(entityName).resolvedSymbol;
82418292
}
@@ -8267,10 +8318,10 @@ module ts {
82678318
return getSymbolOfNode(node.parent);
82688319
}
82698320

8270-
if (node.kind === SyntaxKind.Identifier && isInRightSideOfImportOrExportAssignment(node)) {
8321+
if (node.kind === SyntaxKind.Identifier && isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
82718322
return node.parent.kind === SyntaxKind.ExportAssignment
82728323
? getSymbolOfEntityName(<Identifier>node)
8273-
: getSymbolOfPartOfRightHandSideOfImport(node);
8324+
: getSymbolOfPartOfRightHandSideOfImport(<Identifier>node);
82748325
}
82758326

82768327
switch (node.kind) {
@@ -8351,7 +8402,7 @@ module ts {
83518402
return symbol && getTypeOfSymbol(symbol);
83528403
}
83538404

8354-
if (isInRightSideOfImportOrExportAssignment(node)) {
8405+
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
83558406
var symbol = getSymbolInfo(node);
83568407
var declaredType = symbol && getDeclaredTypeOfSymbol(symbol);
83578408
return declaredType !== unknownType ? declaredType : getTypeOfSymbol(symbol);

src/compiler/commandLineParser.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,9 +183,10 @@ module ts {
183183
break;
184184
// If not a primitive, the possible types are specified in what is effectively a map of options.
185185
default:
186-
var value = (args[i++] || "").toLowerCase();
187-
if (hasProperty(opt.type, value)) {
188-
options[opt.name] = opt.type[value];
186+
var map = <Map<number>>opt.type;
187+
var key = (args[i++] || "").toLowerCase();
188+
if (hasProperty(map, key)) {
189+
options[opt.name] = map[key];
189190
}
190191
else {
191192
errors.push(createCompilerDiagnostic(opt.error));

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ module ts {
120120
const_declarations_must_be_initialized: { code: 1155, category: DiagnosticCategory.Error, key: "'const' declarations must be initialized" },
121121
const_declarations_can_only_be_declared_inside_a_block: { code: 1156, category: DiagnosticCategory.Error, key: "'const' declarations can only be declared inside a block." },
122122
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
123+
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." },
123124
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
124125
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." },
125126
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
@@ -266,6 +267,7 @@ module ts {
266267
An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." },
267268
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." },
268269
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}'." },
270+
Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." },
269271
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
270272
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}'." },
271273
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}'." },
@@ -345,6 +347,9 @@ module ts {
345347
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." },
346348
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}'." },
347349
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}'." },
350+
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." },
351+
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}'." },
352+
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}'." },
348353
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
349354
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." },
350355
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },

src/compiler/diagnosticMessages.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,10 @@
471471
"category": "Error",
472472
"code": 1157
473473
},
474+
"Aliased type cannot be an object type literal. Use an interface declaration instead.": {
475+
"category": "Error",
476+
"code": 1158
477+
},
474478

475479
"Duplicate identifier '{0}'.": {
476480
"category": "Error",
@@ -1064,6 +1068,10 @@
10641068
"category": "Error",
10651069
"code": 2455
10661070
},
1071+
"Type alias '{0}' circularly references itself.": {
1072+
"category": "Error",
1073+
"code": 2456
1074+
},
10671075

10681076
"Import declaration '{0}' is using private name '{1}'.": {
10691077
"category": "Error",
@@ -1381,6 +1389,18 @@
13811389
"category": "Error",
13821390
"code": 4078
13831391
},
1392+
"Exported type alias '{0}' has or is using name '{1}' from external module {2} but cannot be named.": {
1393+
"category": "Error",
1394+
"code": 4079
1395+
},
1396+
"Exported type alias '{0}' has or is using name '{1}' from private module '{2}'.": {
1397+
"category": "Error",
1398+
"code": 4080
1399+
},
1400+
"Exported type alias '{0}' has or is using private name '{1}'.": {
1401+
"category": "Error",
1402+
"code": 4081
1403+
},
13841404

13851405

13861406
"The current host does not support the '{0}' option.": {

src/compiler/emitter.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2566,6 +2566,32 @@ module ts {
25662566
}
25672567
}
25682568

2569+
function emitTypeAliasDeclaration(node: TypeAliasDeclaration) {
2570+
if (resolver.isDeclarationVisible(node)) {
2571+
emitJsDocComments(node);
2572+
emitDeclarationFlags(node);
2573+
write("type ");
2574+
emitSourceTextOfNode(node.name);
2575+
write(" = ");
2576+
getSymbolVisibilityDiagnosticMessage = getTypeAliasDeclarationVisibilityError;
2577+
resolver.writeTypeAtLocation(node.type, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
2578+
write(";");
2579+
writeLine();
2580+
}
2581+
function getTypeAliasDeclarationVisibilityError(symbolAccesibilityResult: SymbolAccessiblityResult) {
2582+
var diagnosticMessage = symbolAccesibilityResult.errorModuleName ?
2583+
symbolAccesibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
2584+
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
2585+
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_private_module_2 :
2586+
Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1;
2587+
return {
2588+
diagnosticMessage: diagnosticMessage,
2589+
errorNode: node,
2590+
typeName: node.name
2591+
};
2592+
}
2593+
}
2594+
25692595
function emitEnumDeclaration(node: EnumDeclaration) {
25702596
if (resolver.isDeclarationVisible(node)) {
25712597
emitJsDocComments(node);
@@ -3163,6 +3189,8 @@ module ts {
31633189
return emitInterfaceDeclaration(<InterfaceDeclaration>node);
31643190
case SyntaxKind.ClassDeclaration:
31653191
return emitClassDeclaration(<ClassDeclaration>node);
3192+
case SyntaxKind.TypeAliasDeclaration:
3193+
return emitTypeAliasDeclaration(<TypeAliasDeclaration>node);
31663194
case SyntaxKind.EnumMember:
31673195
return emitEnumMemberDeclaration(<EnumMember>node);
31683196
case SyntaxKind.EnumDeclaration:

0 commit comments

Comments
 (0)