diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c9f9d6bf6e3..d8da47fb566 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -326,6 +326,9 @@ module ts { case SyntaxKind.InterfaceDeclaration: bindDeclaration(node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes); break; + case SyntaxKind.TypeAliasDeclaration: + bindDeclaration(node, SymbolFlags.TypeAlias, SymbolFlags.TypeAliasExcludes); + break; case SyntaxKind.EnumDeclaration: bindDeclaration(node, SymbolFlags.Enum, SymbolFlags.EnumExcludes); break; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 229fcf51f17..876742d9edf 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -86,6 +86,7 @@ module ts { emitFiles: invokeEmitter, getParentOfSymbol: getParentOfSymbol, getTypeOfSymbol: getTypeOfSymbol, + getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol, getPropertiesOfType: getPropertiesOfType, getPropertyOfType: getPropertyOfType, getSignaturesOfType: getSignaturesOfType, @@ -188,6 +189,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; } @@ -1907,6 +1909,24 @@ module ts { return links.declaredType; } + function getDeclaredTypeOfTypeAlias(symbol: Symbol): Type { + var links = getSymbolLinks(symbol); + if (!links.declaredType) { + links.declaredType = resolvingType; + var declaration = 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 = 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) { @@ -1946,6 +1966,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); } @@ -7304,6 +7327,10 @@ module ts { } } + function checkTypeAliasDeclaration(node: TypeAliasDeclaration) { + checkSourceElement(node.type); + } + function getConstantValueForExpression(node: Expression): number { var isNegative = false; if (node.kind === SyntaxKind.PrefixOperator) { @@ -7596,6 +7623,8 @@ module ts { return checkClassDeclaration(node); case SyntaxKind.InterfaceDeclaration: return checkInterfaceDeclaration(node); + case SyntaxKind.TypeAliasDeclaration: + return checkTypeAliasDeclaration(node); case SyntaxKind.EnumDeclaration: return checkEnumDeclaration(node); case SyntaxKind.ModuleDeclaration: @@ -7840,6 +7869,7 @@ module ts { case SyntaxKind.TypeParameter: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.EnumDeclaration: return true; } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index ac2a79c603d..b1de70a8b58 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -261,6 +261,7 @@ module ts { Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2445, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible within class '{1}' and its subclasses." }, Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1: { code: 2446, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible through an instance of class '{1}'." }, The_0_operator_is_not_allowed_for_boolean_types_Consider_using_1_instead: { code: 2447, category: DiagnosticCategory.Error, key: "The '{0}' operator is not allowed for boolean types. Consider using '{1}' instead." }, + Type_alias_0_circularly_references_itself: { code: 2448, 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}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index d8895d15144..274cc0fd9be 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1036,6 +1036,10 @@ "category": "Error", "code": 2447 }, + "Type alias '{0}' circularly references itself.": { + "category": "Error", + "code": 2448 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index c755205ee3a..1fd1e3c2178 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -333,6 +333,9 @@ module ts { children((node).typeParameters) || children((node).baseTypes) || children((node).members); + case SyntaxKind.TypeAliasDeclaration: + return child((node).name) || + child((node).type); case SyntaxKind.EnumDeclaration: return child((node).name) || children((node).members); @@ -478,6 +481,7 @@ module ts { case SyntaxKind.SetAccessor: case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: @@ -540,6 +544,7 @@ module ts { return node; case SyntaxKind.EnumDeclaration: case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: // early exit cases - declarations cannot be nested in classes @@ -3075,6 +3080,7 @@ module ts { case SyntaxKind.ClassKeyword: case SyntaxKind.ModuleKeyword: case SyntaxKind.EnumKeyword: + case SyntaxKind.TypeKeyword: // When followed by an identifier, these do not start a statement but might // instead be following declarations if (isDeclaration()) { @@ -3626,7 +3632,18 @@ module ts { } return finishNode(node); } - + + function parseTypeAliasDeclaration(pos: number, flags: NodeFlags): TypeAliasDeclaration { + var node = createNode(SyntaxKind.TypeAliasDeclaration, pos); + node.flags = flags; + parseExpected(SyntaxKind.TypeKeyword); + node.name = parseIdentifier(); + parseExpected(SyntaxKind.EqualsToken); + node.type = parseType(); + parseSemicolon(); + return finishNode(node); + } + function parseAndCheckEnumDeclaration(pos: number, flags: NodeFlags): EnumDeclaration { function isIntegerLiteral(expression: Expression): boolean { function isInteger(literalExpression: LiteralExpression): boolean { @@ -3786,6 +3803,7 @@ module ts { case SyntaxKind.InterfaceKeyword: case SyntaxKind.EnumKeyword: case SyntaxKind.ImportKeyword: + case SyntaxKind.TypeKeyword: // Not true keywords so ensure an identifier follows return lookAhead(() => nextToken() >= SyntaxKind.Identifier); case SyntaxKind.ModuleKeyword: @@ -3841,6 +3859,9 @@ module ts { case SyntaxKind.InterfaceKeyword: result = parseInterfaceDeclaration(pos, flags); break; + case SyntaxKind.TypeKeyword: + result = parseTypeAliasDeclaration(pos, flags); + break; case SyntaxKind.EnumKeyword: result = parseAndCheckEnumDeclaration(pos, flags); break; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 81d16b5f487..75b14801ae7 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -80,6 +80,7 @@ module ts { "throw": SyntaxKind.ThrowKeyword, "true": SyntaxKind.TrueKeyword, "try": SyntaxKind.TryKeyword, + "type": SyntaxKind.TypeKeyword, "typeof": SyntaxKind.TypeOfKeyword, "var": SyntaxKind.VarKeyword, "void": SyntaxKind.VoidKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ea58b1166c6..0df11239107 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -132,6 +132,7 @@ module ts { NumberKeyword, SetKeyword, StringKeyword, + TypeKeyword, // Parse tree nodes Missing, // Names @@ -202,6 +203,7 @@ module ts { FunctionBlock, ClassDeclaration, InterfaceDeclaration, + TypeAliasDeclaration, EnumDeclaration, ModuleDeclaration, ModuleBlock, @@ -518,6 +520,10 @@ module ts { members: NodeArray; } + export interface TypeAliasDeclaration extends Declaration { + type: TypeNode; + } + export interface EnumMember extends Declaration { initializer?: Expression; } @@ -643,6 +649,7 @@ module ts { emitFiles(targetSourceFile?: SourceFile): EmitResult; getParentOfSymbol(symbol: Symbol): Symbol; getTypeOfSymbol(symbol: Symbol): Type; + getDeclaredTypeOfSymbol(symbol: Symbol): Type; getPropertiesOfType(type: Type): Symbol[]; getPropertyOfType(type: Type, propertyName: string): Symbol; getSignaturesOfType(type: Type, kind: SignatureKind): Signature[]; @@ -780,22 +787,23 @@ module ts { ConstructSignature = 0x00010000, // Construct signature IndexSignature = 0x00020000, // Index signature TypeParameter = 0x00040000, // Type parameter + TypeAlias = 0x00080000, // Type alias // Export markers (see comment in declareModuleMember in binder) - ExportValue = 0x00080000, // Exported value marker - ExportType = 0x00100000, // Exported type marker - ExportNamespace = 0x00200000, // Exported namespace marker + ExportValue = 0x00100000, // Exported value marker + ExportType = 0x00200000, // Exported type marker + ExportNamespace = 0x00400000, // Exported namespace marker - Import = 0x00400000, // Import - Instantiated = 0x00800000, // Instantiated symbol - Merged = 0x01000000, // Merged symbol (created during program binding) - Transient = 0x02000000, // Transient symbol (created during type check) - Prototype = 0x04000000, // Prototype property (no source representation) - UnionProperty = 0x08000000, // Property in union type + Import = 0x00800000, // Import + Instantiated = 0x01000000, // Instantiated symbol + Merged = 0x02000000, // Merged symbol (created during program binding) + Transient = 0x04000000, // Transient symbol (created during type check) + Prototype = 0x08000000, // Prototype property (no source representation) + UnionProperty = 0x10000000, // Property in union type Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor, - Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter, + Type = Class | Interface | Enum | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias, Namespace = ValueModule | NamespaceModule, Module = ValueModule | NamespaceModule, Accessor = GetAccessor | SetAccessor, @@ -815,11 +823,12 @@ module ts { GetAccessorExcludes = Value & ~SetAccessor, SetAccessorExcludes = Value & ~GetAccessor, TypeParameterExcludes = Type & ~TypeParameter, + TypeAliasExcludes = Type, // Imports collide with all other imports with the same name. ImportExcludes = Import, - ModuleMember = Variable | Function | Class | Interface | Enum | Module | Import, + ModuleMember = Variable | Function | Class | Interface | Enum | Module | TypeAlias | Import, ExportHasLocal = Function | Class | Enum | ValueModule, diff --git a/src/services/services.ts b/src/services/services.ts index 162aa4ae201..3050b99c2d4 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -706,6 +706,7 @@ module ts { case SyntaxKind.ClassDeclaration: case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportDeclaration: @@ -1186,6 +1187,9 @@ module ts { // interface Y {} static interfaceElement = "interface"; + // type T = ... + static typeElement = "type"; + // enum E static enumElement = "enum"; @@ -2695,6 +2699,7 @@ module ts { if (flags & SymbolFlags.Class) return ScriptElementKind.classElement; if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; + if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement; if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; if (flags & SymbolFlags.TypeParameter) return ScriptElementKind.typeParameterElement; @@ -2763,6 +2768,7 @@ module ts { case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement; case SyntaxKind.ClassDeclaration: return ScriptElementKind.classElement; case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement; + case SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement; case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement; case SyntaxKind.VariableDeclaration: return ScriptElementKind.variableElement; case SyntaxKind.FunctionDeclaration: return ScriptElementKind.functionElement; @@ -2777,8 +2783,8 @@ module ts { case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement; case SyntaxKind.EnumMember: return ScriptElementKind.variableElement; case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; - return ScriptElementKind.unknown; } + return ScriptElementKind.unknown; } function getSymbolModifiers(symbol: Symbol): string { @@ -2916,6 +2922,16 @@ module ts { addFullSymbolName(symbol); writeTypeParametersOfSymbol(symbol, sourceFile); } + if (symbolFlags & SymbolFlags.TypeAlias) { + addNewLineIfDisplayPartsExist(); + displayParts.push(keywordPart(SyntaxKind.TypeKeyword)); + displayParts.push(spacePart()); + addFullSymbolName(symbol); + displayParts.push(spacePart()); + displayParts.push(punctuationPart(SyntaxKind.EqualsToken)); + displayParts.push(spacePart()); + displayParts.push.apply(displayParts, typeToDisplayParts(typeResolver, typeResolver.getDeclaredTypeOfSymbol(symbol), enclosingDeclaration)); + } if (symbolFlags & SymbolFlags.Enum) { addNewLineIfDisplayPartsExist(); displayParts.push(keywordPart(SyntaxKind.EnumKeyword)); @@ -4503,6 +4519,7 @@ module ts { case SyntaxKind.TypeParameter: case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.TypeLiteral: return SemanticMeaning.Type;