From 65f98b7ba32fd7340908b20dbf4344c66211ae25 Mon Sep 17 00:00:00 2001 From: Paul Johnston Date: Thu, 29 Dec 2016 10:32:40 -0700 Subject: [PATCH 1/9] Adds override keyword and initial modifier flags checks. --- src/compiler/binder.ts | 1 + src/compiler/checker.ts | 43 +++++++++++++++++++ src/compiler/commandLineParser.ts | 5 +++ src/compiler/diagnosticMessages.json | 4 ++ src/compiler/emitter.ts | 1 + src/compiler/parser.ts | 4 ++ src/compiler/program.ts | 1 + src/compiler/scanner.ts | 1 + src/compiler/transformers/ts.ts | 1 + src/compiler/types.ts | 5 ++- src/compiler/utilities.ts | 2 + src/services/jsDoc.ts | 1 + tests/baselines/reference/overrideKeyword.js | 34 +++++++++++++++ .../reference/overrideKeyword.symbols | 17 ++++++++ .../baselines/reference/overrideKeyword.types | 19 ++++++++ tests/cases/compiler/overrideKeyword.ts | 8 ++++ 16 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/overrideKeyword.js create mode 100644 tests/baselines/reference/overrideKeyword.symbols create mode 100644 tests/baselines/reference/overrideKeyword.types create mode 100644 tests/cases/compiler/overrideKeyword.ts diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 39ff7a088dc42..d3a133149aac4 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3104,6 +3104,7 @@ namespace ts { case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: case SyntaxKind.NonNullExpression: + case SyntaxKind.OverrideKeyword: case SyntaxKind.ReadonlyKeyword: // These nodes are TypeScript syntax. transformFlags |= TransformFlags.AssertTypeScript; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9e4e81e3da918..d001f28afacfb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15770,6 +15770,21 @@ namespace ts { if (getModifierFlags(node) & ModifierFlags.Abstract && node.body) { error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); } + + // Is this the correct time to make assertions against the inheritance chain? + // Have all other methods been resolved? Probably need to record that an override exists + // and perform the actual resolution later. + if (getModifierFlags(node) & ModifierFlags.Override) { + checkOverrideMethodDeclaration(node); + } + } + + function checkOverrideMethodDeclaration(node: MethodDeclaration) { + forEachEnclosingClass(node, enclosingClass => { + // TODO: save the methodDeclaration node here in a cache and + // perform the actual assertion later. + console.log(`override method ${node.symbol.name} is enclosed by class ${enclosingClass.symbol.name}`); + }); } function checkConstructorDeclaration(node: ConstructorDeclaration) { @@ -20938,6 +20953,9 @@ namespace ts { else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); } + else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); + } else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); } @@ -20971,6 +20989,9 @@ namespace ts { else if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); } + else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override"); + } flags |= ModifierFlags.Static; lastStatic = modifier; break; @@ -21067,6 +21088,25 @@ namespace ts { flags |= ModifierFlags.Async; lastAsync = modifier; break; + + case SyntaxKind.OverrideKeyword: + if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); + } + else if (flags & ModifierFlags.Static) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override"); + } + else if (flags & ModifierFlags.Private) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); + } + else if (flags & ModifierFlags.Abstract) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override"); + } + else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override"); + } + flags |= ModifierFlags.Override; + break; } } @@ -21080,6 +21120,9 @@ namespace ts { else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); } + else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(lastReadonly, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); + } else if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(lastReadonly, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "readonly"); } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 3a4d5c6b1f7a2..bbec03743a93d 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -144,6 +144,11 @@ namespace ts { type: "boolean", description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type, }, + { + name: "noImplicitOverride", + type: "boolean", + description: Diagnostics.Member_function_0_was_marked_override_but_no_matching_definition_was_found_in_the_superclass_chain_1, + }, { name: "noImplicitThis", type: "boolean", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 52fc401d1f151..58fde139f87a8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3279,6 +3279,10 @@ "category": "Message", "code": 90015 }, + "Member function {0} was marked 'override', but no matching definition was found in the superclass chain ({1})": { + "category": "Error", + "code": 90030 + }, "Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": { "category": "Error", "code": 8017 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 69bd4a8b6e1a1..0dfdb8c9b01af 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -324,6 +324,7 @@ namespace ts { case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.StaticKeyword: // Contextual keywords diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 026f844315bbf..8cdf06c5b52ef 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4692,6 +4692,7 @@ namespace ts { case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.ReadonlyKeyword: nextToken(); // ASI takes effect for this modifier. @@ -4776,6 +4777,7 @@ namespace ts { case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.StaticKeyword: case SyntaxKind.ReadonlyKeyword: // When these don't start a declaration, they may be the start of a class member if an identifier @@ -4857,6 +4859,7 @@ namespace ts { case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.AbstractKeyword: case SyntaxKind.StaticKeyword: case SyntaxKind.ReadonlyKeyword: @@ -5154,6 +5157,7 @@ namespace ts { case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.StaticKeyword: case SyntaxKind.ReadonlyKeyword: return true; diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1099e1269120b..3f05de9bf36e8 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1061,6 +1061,7 @@ namespace ts { case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.ReadonlyKeyword: case SyntaxKind.DeclareKeyword: case SyntaxKind.AbstractKeyword: diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index a03bf733f75c9..51e89a8474c21 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -99,6 +99,7 @@ namespace ts { "null": SyntaxKind.NullKeyword, "number": SyntaxKind.NumberKeyword, "object": SyntaxKind.ObjectKeyword, + "override": SyntaxKind.OverrideKeyword, "package": SyntaxKind.PackageKeyword, "private": SyntaxKind.PrivateKeyword, "protected": SyntaxKind.ProtectedKeyword, diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 775f60355d8bc..fa3b7865c5ec1 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -306,6 +306,7 @@ namespace ts { case SyntaxKind.ConstKeyword: case SyntaxKind.DeclareKeyword: case SyntaxKind.ReadonlyKeyword: + case SyntaxKind.OverrideKeyword: // TypeScript accessibility and readonly modifiers are elided. case SyntaxKind.ArrayType: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 954ad21ba29af..d78f9012c5897 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -155,6 +155,7 @@ namespace ts { PrivateKeyword, ProtectedKeyword, PublicKeyword, + OverrideKeyword, StaticKeyword, YieldKeyword, // Contextual keywords @@ -453,6 +454,7 @@ namespace ts { Abstract = 1 << 7, // Class/Method/ConstructSignature Async = 1 << 8, // Property/Method/Function Default = 1 << 9, // Function/Class (export default declaration) + Override = 1 << 10, // Property/Method Const = 1 << 11, // Variable declaration HasComputedFlags = 1 << 29, // Modifier flags have been computed @@ -461,7 +463,7 @@ namespace ts { ParameterPropertyModifier = AccessibilityModifier | Readonly, NonPublicAccessibilityModifier = Private | Protected, - TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const, + TypeScriptModifier = Ambient | Public | Private | Protected | Override | Readonly | Abstract | Const, ExportDefault = Export | Default, } @@ -532,6 +534,7 @@ namespace ts { | Token | Token | Token + | Token | Token | Token ; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 192ef888b11e9..67e1d5e7f74e5 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1964,6 +1964,7 @@ namespace ts { case SyntaxKind.PublicKeyword: case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.ReadonlyKeyword: case SyntaxKind.StaticKeyword: return true; @@ -3123,6 +3124,7 @@ namespace ts { case SyntaxKind.DefaultKeyword: return ModifierFlags.Default; case SyntaxKind.AsyncKeyword: return ModifierFlags.Async; case SyntaxKind.ReadonlyKeyword: return ModifierFlags.Readonly; + case SyntaxKind.OverrideKeyword: return ModifierFlags.Override; } return ModifierFlags.None; } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 08a51a63e63af..5fb3eabf886ab 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -30,6 +30,7 @@ namespace ts.JsDoc { "private", "property", "public", + "override", "requires", "returns", "see", diff --git a/tests/baselines/reference/overrideKeyword.js b/tests/baselines/reference/overrideKeyword.js new file mode 100644 index 0000000000000..56acabe8bd1a6 --- /dev/null +++ b/tests/baselines/reference/overrideKeyword.js @@ -0,0 +1,34 @@ +//// [overrideKeyword.ts] +class Base { + public toString() { return "base"; }; +} + +class Derived extends Base { + /** @override */ + public override toString() { return "derived"; }; +} + + +//// [overrideKeyword.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Base = (function () { + function Base() { + } + Base.prototype.toString = function () { return "base"; }; + ; + return Base; +}()); +var Derived = (function (_super) { + __extends(Derived, _super); + function Derived() { + return _super.apply(this, arguments) || this; + } + /** @override */ + Derived.prototype.toString = function () { return "derived"; }; + ; + return Derived; +}(Base)); diff --git a/tests/baselines/reference/overrideKeyword.symbols b/tests/baselines/reference/overrideKeyword.symbols new file mode 100644 index 0000000000000..310ce18f6f286 --- /dev/null +++ b/tests/baselines/reference/overrideKeyword.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/overrideKeyword.ts === +class Base { +>Base : Symbol(Base, Decl(overrideKeyword.ts, 0, 0)) + + public toString() { return "base"; }; +>toString : Symbol(Base.toString, Decl(overrideKeyword.ts, 0, 12)) +} + +class Derived extends Base { +>Derived : Symbol(Derived, Decl(overrideKeyword.ts, 2, 1)) +>Base : Symbol(Base, Decl(overrideKeyword.ts, 0, 0)) + + /** @override */ + public override toString() { return "derived"; }; +>toString : Symbol(Derived.toString, Decl(overrideKeyword.ts, 4, 28)) +} + diff --git a/tests/baselines/reference/overrideKeyword.types b/tests/baselines/reference/overrideKeyword.types new file mode 100644 index 0000000000000..9748e915a7ce4 --- /dev/null +++ b/tests/baselines/reference/overrideKeyword.types @@ -0,0 +1,19 @@ +=== tests/cases/compiler/overrideKeyword.ts === +class Base { +>Base : Base + + public toString() { return "base"; }; +>toString : () => string +>"base" : "base" +} + +class Derived extends Base { +>Derived : Derived +>Base : Base + + /** @override */ + public override toString() { return "derived"; }; +>toString : () => string +>"derived" : "derived" +} + diff --git a/tests/cases/compiler/overrideKeyword.ts b/tests/cases/compiler/overrideKeyword.ts new file mode 100644 index 0000000000000..e843594862fb6 --- /dev/null +++ b/tests/cases/compiler/overrideKeyword.ts @@ -0,0 +1,8 @@ +class Base { + public toString() { return "base"; }; +} + +class Derived extends Base { + /** @override */ + public override toString() { return "derived"; }; +} From fb705a6124c2d67ad1b2e36ec8d1350860c1567d Mon Sep 17 00:00:00 2001 From: Paul Johnston Date: Wed, 4 Jan 2017 00:44:43 -0700 Subject: [PATCH 2/9] Implements override keyword checks and the --noImplicitOverride compiler option. * Moves `OverrideKeyword` to the more appropriate contextual keyword section (types.ts) * Introduces the `CompilerOptions.noImplicitOverride` boolean option (types.ts). * Moves the location for performing override assertions to `checkKindsOfPropertyMemberOverrides` as suggested (checker.ts). * Adds several other diagnostic messages (diagnosticMessages.json). * Improves the breadth of the `overrideKeyword.ts` test case. * Adds a new `noImplicitOverride.ts` test case. --- src/compiler/checker.ts | 161 ++++++++---- src/compiler/commandLineParser.ts | 2 +- src/compiler/declarationEmitter.ts | 3 + src/compiler/diagnosticMessages.json | 26 +- src/compiler/emitter.ts | 2 +- src/compiler/types.ts | 3 +- src/harness/unittests/transpile.ts | 4 + src/server/protocol.ts | 7 +- .../reference/noImplicitOverride.errors.txt | 83 +++++++ .../baselines/reference/noImplicitOverride.js | 135 ++++++++++ .../reference/overrideKeyword.errors.txt | 147 +++++++++++ tests/baselines/reference/overrideKeyword.js | 231 ++++++++++++++++-- tests/cases/compiler/noImplicitOverride.ts | 54 ++++ tests/cases/compiler/overrideKeyword.ts | 91 ++++++- 14 files changed, 881 insertions(+), 68 deletions(-) create mode 100644 tests/baselines/reference/noImplicitOverride.errors.txt create mode 100644 tests/baselines/reference/noImplicitOverride.js create mode 100644 tests/baselines/reference/overrideKeyword.errors.txt create mode 100644 tests/cases/compiler/noImplicitOverride.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d001f28afacfb..b09eae7b19b88 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15756,6 +15756,10 @@ namespace ts { checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name); checkVariableLikeDeclaration(node); + + if (getModifierFlags(node) & ModifierFlags.Override) { + checkOverrideDeclaration(node); + } } function checkMethodDeclaration(node: MethodDeclaration) { @@ -15771,20 +15775,15 @@ namespace ts { error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name)); } - // Is this the correct time to make assertions against the inheritance chain? - // Have all other methods been resolved? Probably need to record that an override exists - // and perform the actual resolution later. if (getModifierFlags(node) & ModifierFlags.Override) { - checkOverrideMethodDeclaration(node); + checkOverrideDeclaration(node); } } - function checkOverrideMethodDeclaration(node: MethodDeclaration) { - forEachEnclosingClass(node, enclosingClass => { - // TODO: save the methodDeclaration node here in a cache and - // perform the actual assertion later. - console.log(`override method ${node.symbol.name} is enclosed by class ${enclosingClass.symbol.name}`); - }); + function checkOverrideDeclaration(node: MethodDeclaration | PropertyDeclaration | AccessorDeclaration) { + if (node.questionToken) { + error(node, Diagnostics.override_modifier_cannot_be_used_with_an_optional_property_declaration); + } } function checkConstructorDeclaration(node: ConstructorDeclaration) { @@ -15899,6 +15898,11 @@ namespace ts { checkGrammarFunctionLikeDeclaration(node) || checkGrammarAccessor(node) || checkGrammarComputedPropertyName(node.name); checkDecorators(node); + + if (getModifierFlags(node) & ModifierFlags.Override) { + checkOverrideDeclaration(node); + } + checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { @@ -15925,6 +15929,9 @@ namespace ts { if (hasModifier(node, ModifierFlags.Abstract) !== hasModifier(otherAccessor, ModifierFlags.Abstract)) { error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract); } + if (hasModifier(node, ModifierFlags.Override) !== hasModifier(otherAccessor, ModifierFlags.Override)) { + error(node.name, Diagnostics.Accessors_must_both_be_override_or_non_override); + } // TypeScript 1.0 spec (April 2014): 4.5 // If both accessors include type annotations, the specified types must be identical. @@ -15944,6 +15951,7 @@ namespace ts { else { checkNodeDeferred(node); } + } function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) { @@ -16119,6 +16127,9 @@ namespace ts { else if (deviation & ModifierFlags.Abstract) { error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract); } + else if (deviation & ModifierFlags.Override) { + error(o.name, Diagnostics.Overload_signatures_must_all_be_override_or_non_override); + } }); } } @@ -18318,6 +18329,13 @@ namespace ts { checkKindsOfPropertyMemberOverrides(type, baseType); } } + else { + const properties = createMap(); + for (const prop of getPropertiesOfObjectType(type)) { + properties[prop.name] = prop; + } + checkImplicitPropertyMemberOverrides(type, properties); + } const implementedTypeNodes = getClassImplementsHeritageClauseElements(node); if (implementedTypeNodes) { @@ -18370,6 +18388,44 @@ namespace ts { return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined); } + function checkImplicitPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map): void { + // If the class does not explicitly declare 'extends Object', + // declarations that mask 'Object' members ('toString()', 'hasOwnProperty()', etc...) + // are considered here. + const objectType = getSymbol(globals, "Object", SymbolFlags.Type); + if (!objectType) { + return; + } + for (const name in propertiesToCheck) { + const derived = getTargetSymbol(propertiesToCheck[name]); + const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); + const found = objectType.members[name]; + if (found) { + if (compilerOptions.noImplicitOverride) { + const foundSymbol = getTargetSymbol(found); + let detail = "masks Object." + symbolToString(found); + // assert that the type of the derived + // property matches that of the base property. + if (!isPropertyIdenticalTo(derived, foundSymbol)) { + detail += "). The override declaration (" + + typeToString(getTypeOfSymbol(derived)) + + ") also has a different type signature than the original (" + + typeToString(getTypeOfSymbol(foundSymbol)); + } + error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1, + symbolToString(derived), detail); + } + } + // No matching property found on the object type. It + // is an error for the derived property to falsely + // claim 'override'. + else if (derivedDeclarationFlags & ModifierFlags.Override) { + error(derived.valueDeclaration.name, Diagnostics.Class_member_0_was_marked_override_but_no_matching_definition_was_found_in_any_supertype_of_1, + symbolToString(derived), typeToString(type)); + } + } + } + function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void { // TypeScript 1.0 spec (April 2014): 8.2.3 @@ -18387,9 +18443,17 @@ namespace ts { // derived class instance member variables and accessors, but not by other kinds of members. // NOTE: assignability is checked in checkClassDeclaration + + // Track which symbols in the derived class have not been seen. + const onlyInDerived = createMap(); + for (const prop of getPropertiesOfObjectType(type)) { + onlyInDerived[prop.name] = prop; + } + const baseProperties = getPropertiesOfObjectType(baseType); for (const baseProperty of baseProperties) { const base = getTargetSymbol(baseProperty); + delete onlyInDerived[base.name]; if (base.flags & SymbolFlags.Prototype) { continue; @@ -18422,6 +18486,7 @@ namespace ts { typeToString(type), symbolToString(baseProperty), typeToString(baseType)); } } + } else { // derived overrides base. @@ -18438,6 +18503,16 @@ namespace ts { if ((base.flags & derived.flags & SymbolFlags.Method) || ((base.flags & SymbolFlags.PropertyOrAccessor) && (derived.flags & SymbolFlags.PropertyOrAccessor))) { // method is overridden with method or property/accessor is overridden with property/accessor - correct case + + // Before accepting the correct case, ensure 'override' is marked if --noImplicitOverride is true. + // Abstract members are an exception as override checks are suspended until the implementation solidifies. + if (compilerOptions.noImplicitOverride + && !(derivedDeclarationFlags & ModifierFlags.Abstract) + && !(derivedDeclarationFlags & ModifierFlags.Override)) { + error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1, + symbolToString(derived), "inherited from " + typeToString(baseType)); + } + continue; } @@ -18465,6 +18540,8 @@ namespace ts { } } } + + checkImplicitPropertyMemberOverrides(type, onlyInDerived); } function isAccessor(kind: SyntaxKind): boolean { @@ -21075,38 +21152,38 @@ namespace ts { flags |= ModifierFlags.Abstract; break; - case SyntaxKind.AsyncKeyword: - if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); - } - else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); - } - else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); - } - flags |= ModifierFlags.Async; - lastAsync = modifier; - break; - - case SyntaxKind.OverrideKeyword: - if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); - } - else if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override"); - } - else if (flags & ModifierFlags.Private) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); - } - else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override"); - } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override"); - } - flags |= ModifierFlags.Override; - break; + case SyntaxKind.OverrideKeyword: + if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); + } + else if (flags & ModifierFlags.Static) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override"); + } + else if (flags & ModifierFlags.Private) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); + } + else if (flags & ModifierFlags.Abstract) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override"); + } + else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override"); + } + flags |= ModifierFlags.Override; + break; + + case SyntaxKind.AsyncKeyword: + if (flags & ModifierFlags.Async) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async"); + } + else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent)) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async"); + } + else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async"); + } + flags |= ModifierFlags.Async; + lastAsync = modifier; + break; } } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index bbec03743a93d..3ed6dce09da41 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -147,7 +147,7 @@ namespace ts { { name: "noImplicitOverride", type: "boolean", - description: Diagnostics.Member_function_0_was_marked_override_but_no_matching_definition_was_found_in_the_superclass_chain_1, + description: Diagnostics.Raise_an_error_when_inherited_Slashoverridden_class_members_are_not_explicitly_marked_override, }, { name: "noImplicitThis", diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index cd98622e080a1..78843c58b74bd 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -717,6 +717,9 @@ namespace ts { } function emitClassMemberDeclarationFlags(flags: ModifierFlags) { + if (flags & ModifierFlags.Override) { + write("override "); + } if (flags & ModifierFlags.Private) { write("private "); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 58fde139f87a8..857733db7397e 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1683,6 +1683,10 @@ "category": "Error", "code": 2518 }, + "Overload signatures must all be override or non-override.": { + "category": "Error", + "code": 2519 + }, "Duplicate identifier '{0}'. Compiler uses declaration '{1}' to support async functions.": { "category": "Error", "code": 2520 @@ -2015,6 +2019,10 @@ "category": "Error", "code": 2698 }, + "Accessors must both be override or non-override.": { + "category": "Error", + "code": 2699 + }, "Rest types may only be created from object types.": { "category": "Error", "code": 2700 @@ -3279,10 +3287,26 @@ "category": "Message", "code": 90015 }, - "Member function {0} was marked 'override', but no matching definition was found in the superclass chain ({1})": { + "Raise an error when inherited/overridden class members are not explicitly marked 'override'": { "category": "Error", "code": 90030 }, + "Class member '{0}' was marked 'override', but no matching definition was found in any supertype of '{1}'": { + "category": "Error", + "code": 90032 + }, + "Class member '{0}' must be marked 'override' when noImplicitOverride is enabled ({1})": { + "category": "Error", + "code": 90033 + }, + "override modifier cannot be used with an optional property declaration": { + "category": "Error", + "code": 90034 + }, + "All declarations of an override method must be consecutive.": { + "category": "Error", + "code": 90035 + }, "Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": { "category": "Error", "code": 8017 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 0dfdb8c9b01af..9bb0af116c5f2 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -324,7 +324,6 @@ namespace ts { case SyntaxKind.PrivateKeyword: case SyntaxKind.ProtectedKeyword: case SyntaxKind.PublicKeyword: - case SyntaxKind.OverrideKeyword: case SyntaxKind.StaticKeyword: // Contextual keywords @@ -341,6 +340,7 @@ namespace ts { case SyntaxKind.ModuleKeyword: case SyntaxKind.NamespaceKeyword: case SyntaxKind.NeverKeyword: + case SyntaxKind.OverrideKeyword: case SyntaxKind.ReadonlyKeyword: case SyntaxKind.RequireKeyword: case SyntaxKind.NumberKeyword: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d78f9012c5897..fdd873d8aa3ac 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -155,7 +155,6 @@ namespace ts { PrivateKeyword, ProtectedKeyword, PublicKeyword, - OverrideKeyword, StaticKeyword, YieldKeyword, // Contextual keywords @@ -184,6 +183,7 @@ namespace ts { UndefinedKeyword, FromKeyword, GlobalKeyword, + OverrideKeyword, OfKeyword, // LastKeyword and LastToken // Parse tree nodes @@ -3195,6 +3195,7 @@ namespace ts { noErrorTruncation?: boolean; noFallthroughCasesInSwitch?: boolean; noImplicitAny?: boolean; + noImplicitOverride?: boolean; noImplicitReturns?: boolean; noImplicitThis?: boolean; noUnusedLocals?: boolean; diff --git a/src/harness/unittests/transpile.ts b/src/harness/unittests/transpile.ts index 20552ab9c2e14..df13e7bc80374 100644 --- a/src/harness/unittests/transpile.ts +++ b/src/harness/unittests/transpile.ts @@ -341,6 +341,10 @@ var x = 0;`, { options: { compilerOptions: { noImplicitAny: true }, fileName: "input.js", reportDiagnostics: true } }); + transpilesCorrectly("Supports setting 'noImplicitOverride'", "x;", { + options: { compilerOptions: { noImplicitOverride: true }, fileName: "input.js", reportDiagnostics: true } + }); + transpilesCorrectly("Supports setting 'noImplicitReturns'", "x;", { options: { compilerOptions: { noImplicitReturns: true }, fileName: "input.js", reportDiagnostics: true } }); diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 680b81dff9986..dd1467fbae4cb 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -417,7 +417,7 @@ namespace ts.server.protocol { startOffset: number; /** - * Position (can be specified instead of line/offset pair) + * Position (can be specified instead of line/offset pair) */ /* @internal */ startPosition?: number; @@ -433,7 +433,7 @@ namespace ts.server.protocol { endOffset: number; /** - * Position (can be specified instead of line/offset pair) + * Position (can be specified instead of line/offset pair) */ /* @internal */ endPosition?: number; @@ -445,7 +445,7 @@ namespace ts.server.protocol { } /** - * Response for GetCodeFixes request. + * Response for GetCodeFixes request. */ export interface GetCodeFixesResponse extends Response { body?: CodeAction[]; @@ -2237,6 +2237,7 @@ namespace ts.server.protocol { noErrorTruncation?: boolean; noFallthroughCasesInSwitch?: boolean; noImplicitAny?: boolean; + noImplicitOverride?: boolean; noImplicitReturns?: boolean; noImplicitThis?: boolean; noUnusedLocals?: boolean; diff --git a/tests/baselines/reference/noImplicitOverride.errors.txt b/tests/baselines/reference/noImplicitOverride.errors.txt new file mode 100644 index 0000000000000..8872952c500b5 --- /dev/null +++ b/tests/baselines/reference/noImplicitOverride.errors.txt @@ -0,0 +1,83 @@ +tests/cases/compiler/noImplicitOverride.ts(10,5): error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +tests/cases/compiler/noImplicitOverride.ts(11,5): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +tests/cases/compiler/noImplicitOverride.ts(17,5): error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) +tests/cases/compiler/noImplicitOverride.ts(18,5): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) +tests/cases/compiler/noImplicitOverride.ts(24,5): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty). The override declaration ((prop: string) => number) also has a different type signature than the original ((v: string) => boolean) +tests/cases/compiler/noImplicitOverride.ts(30,12): error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/noImplicitOverride.ts(34,9): error TS90033: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/noImplicitOverride.ts(42,5): error TS1070: 'override' modifier cannot appear on a type member. +tests/cases/compiler/noImplicitOverride.ts(51,29): error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + + +==== tests/cases/compiler/noImplicitOverride.ts (9 errors) ==== + + class Base { + get name(): string { + return 'Base'; + } + public userId: number = 1; + } + + class RejectWhenOverrideMissingOnInheritedMethod extends Object { + toString(): string { return 'foo'; }; + ~~~~~~~~ +!!! error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) + hasOwnProperty(prop: string): boolean { + ~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) + return super.hasOwnProperty(prop); + } + } + + class RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember { + toString(): string { return 'foo'; }; + ~~~~~~~~ +!!! error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) + hasOwnProperty(prop: string): boolean { + ~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) + return false; + } + } + + class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { + hasOwnProperty(prop: string): number { + ~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty). The override declaration ((prop: string) => number) also has a different type signature than the original ((v: string) => boolean) + return -1; + } + } + + class RejectWhenOverrideMissingOnInheritedProperty extends Base { + public userId = 2; + ~~~~~~ +!!! error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + } + + class RejectWhenOverrideMissingOnInheritedAccessor extends Base { + get name(): string { return 'foo'; }; + ~~~~ +!!! error TS90033: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + } + + interface Shape { + getWidth(): number; + } + + interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape { + override getWidth(): number; + ~~~~~~~~ +!!! error TS1070: 'override' modifier cannot appear on a type member. + } + + interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape { + // abstract members don't need to be declared override + getWidth(): number; + } + + class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { + /** @override */ public userId: number = 2; + ~~~~~~ +!!! error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + } + \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitOverride.js b/tests/baselines/reference/noImplicitOverride.js new file mode 100644 index 0000000000000..ca1cee5d662e6 --- /dev/null +++ b/tests/baselines/reference/noImplicitOverride.js @@ -0,0 +1,135 @@ +//// [noImplicitOverride.ts] + +class Base { + get name(): string { + return 'Base'; + } + public userId: number = 1; +} + +class RejectWhenOverrideMissingOnInheritedMethod extends Object { + toString(): string { return 'foo'; }; + hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } +} + +class RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember { + toString(): string { return 'foo'; }; + hasOwnProperty(prop: string): boolean { + return false; + } +} + +class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { + hasOwnProperty(prop: string): number { + return -1; + } +} + +class RejectWhenOverrideMissingOnInheritedProperty extends Base { + public userId = 2; +} + +class RejectWhenOverrideMissingOnInheritedAccessor extends Base { + get name(): string { return 'foo'; }; +} + +interface Shape { + getWidth(): number; +} + +interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape { + override getWidth(): number; +} + +interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape { + // abstract members don't need to be declared override + getWidth(): number; +} + +class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { + /** @override */ public userId: number = 2; +} + + +//// [noImplicitOverride.js] +var __extends = (this && this.__extends) || function (d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +}; +var Base = (function () { + function Base() { + this.userId = 1; + } + Object.defineProperty(Base.prototype, "name", { + get: function () { + return 'Base'; + }, + enumerable: true, + configurable: true + }); + return Base; +}()); +var RejectWhenOverrideMissingOnInheritedMethod = (function (_super) { + __extends(RejectWhenOverrideMissingOnInheritedMethod, _super); + function RejectWhenOverrideMissingOnInheritedMethod() { + return _super.apply(this, arguments) || this; + } + RejectWhenOverrideMissingOnInheritedMethod.prototype.toString = function () { return 'foo'; }; + ; + RejectWhenOverrideMissingOnInheritedMethod.prototype.hasOwnProperty = function (prop) { + return _super.prototype.hasOwnProperty.call(this, prop); + }; + return RejectWhenOverrideMissingOnInheritedMethod; +}(Object)); +var RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember = (function () { + function RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember() { + } + RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember.prototype.toString = function () { return 'foo'; }; + ; + RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember.prototype.hasOwnProperty = function (prop) { + return false; + }; + return RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember; +}()); +var RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember = (function () { + function RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember() { + } + RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember.prototype.hasOwnProperty = function (prop) { + return -1; + }; + return RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember; +}()); +var RejectWhenOverrideMissingOnInheritedProperty = (function (_super) { + __extends(RejectWhenOverrideMissingOnInheritedProperty, _super); + function RejectWhenOverrideMissingOnInheritedProperty() { + var _this = _super.apply(this, arguments) || this; + _this.userId = 2; + return _this; + } + return RejectWhenOverrideMissingOnInheritedProperty; +}(Base)); +var RejectWhenOverrideMissingOnInheritedAccessor = (function (_super) { + __extends(RejectWhenOverrideMissingOnInheritedAccessor, _super); + function RejectWhenOverrideMissingOnInheritedAccessor() { + return _super.apply(this, arguments) || this; + } + Object.defineProperty(RejectWhenOverrideMissingOnInheritedAccessor.prototype, "name", { + get: function () { return 'foo'; }, + enumerable: true, + configurable: true + }); + ; + return RejectWhenOverrideMissingOnInheritedAccessor; +}(Base)); +var FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation = (function (_super) { + __extends(FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation, _super); + function FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation() { + var _this = _super.apply(this, arguments) || this; + /** @override */ _this.userId = 2; + return _this; + } + return FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation; +}(Base)); diff --git a/tests/baselines/reference/overrideKeyword.errors.txt b/tests/baselines/reference/overrideKeyword.errors.txt new file mode 100644 index 0000000000000..55a852ae9eb98 --- /dev/null +++ b/tests/baselines/reference/overrideKeyword.errors.txt @@ -0,0 +1,147 @@ +tests/cases/compiler/overrideKeyword.ts(4,12): error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) +tests/cases/compiler/overrideKeyword.ts(14,5): error TS90033: Class member 'toStringAbstract' must be marked 'override' when noImplicitOverride is enabled (inherited from AbstractBase) +tests/cases/compiler/overrideKeyword.ts(25,5): error TS90034: override modifier cannot be used with an optional property declaration +tests/cases/compiler/overrideKeyword.ts(29,14): error TS1243: 'abstract' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeyword.ts(33,14): error TS1243: 'static' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeyword.ts(36,7): error TS2415: Class 'RejectWhenAttemptToOverridePrivateMethod' incorrectly extends base class 'Base'. + Types have separate declarations of a private property 'toStringPrivate'. +tests/cases/compiler/overrideKeyword.ts(37,13): error TS1243: 'private' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeyword.ts(41,21): error TS1030: 'override' modifier already seen. +tests/cases/compiler/overrideKeyword.ts(45,14): error TS1029: 'public' modifier must precede 'override' modifier. +tests/cases/compiler/overrideKeyword.ts(49,21): error TS90032: Class member 'iDontExist' was marked 'override', but no matching definition was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' +tests/cases/compiler/overrideKeyword.ts(52,7): error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. + Types of property 'getMeaningOfLife' are incompatible. + Type '() => string' is not assignable to type '() => number'. + Type 'string' is not assignable to type 'number'. +tests/cases/compiler/overrideKeyword.ts(57,18): error TS2699: Accessors must both be override or non-override. +tests/cases/compiler/overrideKeyword.ts(60,9): error TS2699: Accessors must both be override or non-override. +tests/cases/compiler/overrideKeyword.ts(67,14): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) +tests/cases/compiler/overrideKeyword.ts(71,12): error TS90033: Class member 'getMeaningOfLife' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/overrideKeyword.ts(75,14): error TS90033: Class member 'propertyIsEnumerable' must be marked 'override' when noImplicitOverride is enabled (masks Object.propertyIsEnumerable) + + +==== tests/cases/compiler/overrideKeyword.ts (16 errors) ==== + + abstract class AbstractBase { + static toStringStatic(): string { return 'static member'; } + public toString(): string { return 'instance member'; }; + ~~~~~~~~ +!!! error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) + abstract toStringAbstract(): string; + private toStringPrivate(): string { return 'private member'; } + getMeaningOfLife(): number { return 42; } + public wasDisposed?: boolean; + } + + class Base extends AbstractBase { + private name_: string; + + toStringAbstract(): string { return 'implementation of abstract member'; }; + ~~~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'toStringAbstract' must be marked 'override' when noImplicitOverride is enabled (inherited from AbstractBase) + + get name() { + return this.name_; + } + + set name(name: string) { + this.name_ = name; + } + + // override cannot be used with optional property. + public override wasDisposed?: boolean; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS90034: override modifier cannot be used with an optional property declaration + } + + abstract class RejectWhenAttemptToOverrideAbstractMethod extends AbstractBase { + abstract override toStringAbstract(): string; + ~~~~~~~~ +!!! error TS1243: 'abstract' modifier cannot be used with 'override' modifier. + } + + class RejectWhenAttemptToOverrideStaticMethod extends Base { + override static toStringStatic() { return ''; }; + ~~~~~~ +!!! error TS1243: 'static' modifier cannot be used with 'override' modifier. + } + + class RejectWhenAttemptToOverridePrivateMethod extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2415: Class 'RejectWhenAttemptToOverridePrivateMethod' incorrectly extends base class 'Base'. +!!! error TS2415: Types have separate declarations of a private property 'toStringPrivate'. + private override toStringPrivate() { return ''; }; + ~~~~~~~~ +!!! error TS1243: 'private' modifier cannot be used with 'override' modifier. + } + + class RejectWhenOverrideIsRepeated extends Base { + public override override toString() { return ''; }; + ~~~~~~~~ +!!! error TS1030: 'override' modifier already seen. + } + + class RejectWhenOverridePrecedesAccessModifier extends Base { + override public toString() { return ''; }; + ~~~~~~ +!!! error TS1029: 'public' modifier must precede 'override' modifier. + } + + class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + public override iDontExist() { return ''; }; + ~~~~~~~~~~ +!!! error TS90032: Class member 'iDontExist' was marked 'override', but no matching definition was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' + } + + class RejectWhenOverrideHasMismatchedType extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. +!!! error TS2415: Types of property 'getMeaningOfLife' are incompatible. +!!! error TS2415: Type '() => string' is not assignable to type '() => number'. +!!! error TS2415: Type 'string' is not assignable to type 'number'. + override getMeaningOfLife(): string { return 'forty-two'; }; + } + + class RejectWhenAccessorNotBothOverride extends Base { + override get name() { + ~~~~ +!!! error TS2699: Accessors must both be override or non-override. + return 'hardcoded value'; + } + set name(n: string) { + ~~~~ +!!! error TS2699: Accessors must both be override or non-override. + } + } + + /* @mhegazy: is this an appropriate test for consecutive declarations? */ + class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + + override hasOwnProperty(prop: string): boolean { + ~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) + return super.hasOwnProperty(prop); + } + + public getMeaningOfLife(): number { + ~~~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'getMeaningOfLife' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { + ~~~~~~~~~~~~~~~~~~~~ +!!! error TS90033: Class member 'propertyIsEnumerable' must be marked 'override' when noImplicitOverride is enabled (masks Object.propertyIsEnumerable) + return super.propertyIsEnumerable(prop); + } + + } + + class AcceptWhenOverrideFollowsAccessModifier extends Base { + public override toString() { return ''; }; + } + + class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + public override getMeaningOfLife(): number { return 12; }; + } + \ No newline at end of file diff --git a/tests/baselines/reference/overrideKeyword.js b/tests/baselines/reference/overrideKeyword.js index 56acabe8bd1a6..84621b2bbd143 100644 --- a/tests/baselines/reference/overrideKeyword.js +++ b/tests/baselines/reference/overrideKeyword.js @@ -1,11 +1,90 @@ //// [overrideKeyword.ts] -class Base { - public toString() { return "base"; }; + +abstract class AbstractBase { + static toStringStatic(): string { return 'static member'; } + public toString(): string { return 'instance member'; }; + abstract toStringAbstract(): string; + private toStringPrivate(): string { return 'private member'; } + getMeaningOfLife(): number { return 42; } + public wasDisposed?: boolean; +} + +class Base extends AbstractBase { + private name_: string; + + toStringAbstract(): string { return 'implementation of abstract member'; }; + + get name() { + return this.name_; + } + + set name(name: string) { + this.name_ = name; + } + + // override cannot be used with optional property. + public override wasDisposed?: boolean; +} + +abstract class RejectWhenAttemptToOverrideAbstractMethod extends AbstractBase { + abstract override toStringAbstract(): string; +} + +class RejectWhenAttemptToOverrideStaticMethod extends Base { + override static toStringStatic() { return ''; }; +} + +class RejectWhenAttemptToOverridePrivateMethod extends Base { + private override toStringPrivate() { return ''; }; +} + +class RejectWhenOverrideIsRepeated extends Base { + public override override toString() { return ''; }; +} + +class RejectWhenOverridePrecedesAccessModifier extends Base { + override public toString() { return ''; }; +} + +class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + public override iDontExist() { return ''; }; +} + +class RejectWhenOverrideHasMismatchedType extends Base { + override getMeaningOfLife(): string { return 'forty-two'; }; +} + +class RejectWhenAccessorNotBothOverride extends Base { + override get name() { + return 'hardcoded value'; + } + set name(n: string) { + } +} + +/* @mhegazy: is this an appropriate test for consecutive declarations? */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + + override hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } + + public getMeaningOfLife(): number { + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { + return super.propertyIsEnumerable(prop); + } + } -class Derived extends Base { - /** @override */ - public override toString() { return "derived"; }; +class AcceptWhenOverrideFollowsAccessModifier extends Base { + public override toString() { return ''; }; +} + +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + public override getMeaningOfLife(): number { return 12; }; } @@ -15,20 +94,144 @@ var __extends = (this && this.__extends) || function (d, b) { function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; -var Base = (function () { +var AbstractBase = (function () { + function AbstractBase() { + } + AbstractBase.toStringStatic = function () { return 'static member'; }; + AbstractBase.prototype.toString = function () { return 'instance member'; }; + ; + AbstractBase.prototype.toStringPrivate = function () { return 'private member'; }; + AbstractBase.prototype.getMeaningOfLife = function () { return 42; }; + return AbstractBase; +}()); +var Base = (function (_super) { + __extends(Base, _super); function Base() { + return _super.apply(this, arguments) || this; } - Base.prototype.toString = function () { return "base"; }; + Base.prototype.toStringAbstract = function () { return 'implementation of abstract member'; }; ; + Object.defineProperty(Base.prototype, "name", { + get: function () { + return this.name_; + }, + set: function (name) { + this.name_ = name; + }, + enumerable: true, + configurable: true + }); return Base; -}()); -var Derived = (function (_super) { - __extends(Derived, _super); - function Derived() { +}(AbstractBase)); +var RejectWhenAttemptToOverrideAbstractMethod = (function (_super) { + __extends(RejectWhenAttemptToOverrideAbstractMethod, _super); + function RejectWhenAttemptToOverrideAbstractMethod() { + return _super.apply(this, arguments) || this; + } + return RejectWhenAttemptToOverrideAbstractMethod; +}(AbstractBase)); +var RejectWhenAttemptToOverrideStaticMethod = (function (_super) { + __extends(RejectWhenAttemptToOverrideStaticMethod, _super); + function RejectWhenAttemptToOverrideStaticMethod() { + return _super.apply(this, arguments) || this; + } + RejectWhenAttemptToOverrideStaticMethod.toStringStatic = function () { return ''; }; + ; + return RejectWhenAttemptToOverrideStaticMethod; +}(Base)); +var RejectWhenAttemptToOverridePrivateMethod = (function (_super) { + __extends(RejectWhenAttemptToOverridePrivateMethod, _super); + function RejectWhenAttemptToOverridePrivateMethod() { + return _super.apply(this, arguments) || this; + } + RejectWhenAttemptToOverridePrivateMethod.prototype.toStringPrivate = function () { return ''; }; + ; + return RejectWhenAttemptToOverridePrivateMethod; +}(Base)); +var RejectWhenOverrideIsRepeated = (function (_super) { + __extends(RejectWhenOverrideIsRepeated, _super); + function RejectWhenOverrideIsRepeated() { + return _super.apply(this, arguments) || this; + } + RejectWhenOverrideIsRepeated.prototype.toString = function () { return ''; }; + ; + return RejectWhenOverrideIsRepeated; +}(Base)); +var RejectWhenOverridePrecedesAccessModifier = (function (_super) { + __extends(RejectWhenOverridePrecedesAccessModifier, _super); + function RejectWhenOverridePrecedesAccessModifier() { + return _super.apply(this, arguments) || this; + } + RejectWhenOverridePrecedesAccessModifier.prototype.toString = function () { return ''; }; + ; + return RejectWhenOverridePrecedesAccessModifier; +}(Base)); +var RejectWhenOverrideMarkedOnNonInheritedMember = (function (_super) { + __extends(RejectWhenOverrideMarkedOnNonInheritedMember, _super); + function RejectWhenOverrideMarkedOnNonInheritedMember() { + return _super.apply(this, arguments) || this; + } + RejectWhenOverrideMarkedOnNonInheritedMember.prototype.iDontExist = function () { return ''; }; + ; + return RejectWhenOverrideMarkedOnNonInheritedMember; +}(Base)); +var RejectWhenOverrideHasMismatchedType = (function (_super) { + __extends(RejectWhenOverrideHasMismatchedType, _super); + function RejectWhenOverrideHasMismatchedType() { + return _super.apply(this, arguments) || this; + } + RejectWhenOverrideHasMismatchedType.prototype.getMeaningOfLife = function () { return 'forty-two'; }; + ; + return RejectWhenOverrideHasMismatchedType; +}(Base)); +var RejectWhenAccessorNotBothOverride = (function (_super) { + __extends(RejectWhenAccessorNotBothOverride, _super); + function RejectWhenAccessorNotBothOverride() { + return _super.apply(this, arguments) || this; + } + Object.defineProperty(RejectWhenAccessorNotBothOverride.prototype, "name", { + get: function () { + return 'hardcoded value'; + }, + set: function (n) { + }, + enumerable: true, + configurable: true + }); + return RejectWhenAccessorNotBothOverride; +}(Base)); +/* @mhegazy: is this an appropriate test for consecutive declarations? */ +var RejectWhenOverrideDeclarationsAreNotConsecutive = (function (_super) { + __extends(RejectWhenOverrideDeclarationsAreNotConsecutive, _super); + function RejectWhenOverrideDeclarationsAreNotConsecutive() { + return _super.apply(this, arguments) || this; + } + RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.hasOwnProperty = function (prop) { + return _super.prototype.hasOwnProperty.call(this, prop); + }; + RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.getMeaningOfLife = function () { + return 42; + }; + RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.propertyIsEnumerable = function (prop) { + return _super.prototype.propertyIsEnumerable.call(this, prop); + }; + return RejectWhenOverrideDeclarationsAreNotConsecutive; +}(Base)); +var AcceptWhenOverrideFollowsAccessModifier = (function (_super) { + __extends(AcceptWhenOverrideFollowsAccessModifier, _super); + function AcceptWhenOverrideFollowsAccessModifier() { + return _super.apply(this, arguments) || this; + } + AcceptWhenOverrideFollowsAccessModifier.prototype.toString = function () { return ''; }; + ; + return AcceptWhenOverrideFollowsAccessModifier; +}(Base)); +var AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass = (function (_super) { + __extends(AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass, _super); + function AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass() { return _super.apply(this, arguments) || this; } - /** @override */ - Derived.prototype.toString = function () { return "derived"; }; + AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass.prototype.getMeaningOfLife = function () { return 12; }; ; - return Derived; + return AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass; }(Base)); diff --git a/tests/cases/compiler/noImplicitOverride.ts b/tests/cases/compiler/noImplicitOverride.ts new file mode 100644 index 0000000000000..6036d7d8d024e --- /dev/null +++ b/tests/cases/compiler/noImplicitOverride.ts @@ -0,0 +1,54 @@ +// @noImplicitOverride: true +// @target: es5 + +class Base { + get name(): string { + return 'Base'; + } + public userId: number = 1; +} + +class RejectWhenOverrideMissingOnInheritedMethod extends Object { + toString(): string { return 'foo'; }; + hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } +} + +class RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember { + toString(): string { return 'foo'; }; + hasOwnProperty(prop: string): boolean { + return false; + } +} + +class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { + hasOwnProperty(prop: string): number { + return -1; + } +} + +class RejectWhenOverrideMissingOnInheritedProperty extends Base { + public userId = 2; +} + +class RejectWhenOverrideMissingOnInheritedAccessor extends Base { + get name(): string { return 'foo'; }; +} + +interface Shape { + getWidth(): number; +} + +interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape { + override getWidth(): number; +} + +interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape { + // abstract members don't need to be declared override + getWidth(): number; +} + +class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { + /** @override */ public userId: number = 2; +} diff --git a/tests/cases/compiler/overrideKeyword.ts b/tests/cases/compiler/overrideKeyword.ts index e843594862fb6..b7b0cf43baa74 100644 --- a/tests/cases/compiler/overrideKeyword.ts +++ b/tests/cases/compiler/overrideKeyword.ts @@ -1,8 +1,89 @@ -class Base { - public toString() { return "base"; }; +// @noImplicitOverride: true +// @target: es5 + +abstract class AbstractBase { + static toStringStatic(): string { return 'static member'; } + public toString(): string { return 'instance member'; }; + abstract toStringAbstract(): string; + private toStringPrivate(): string { return 'private member'; } + getMeaningOfLife(): number { return 42; } + public wasDisposed?: boolean; +} + +class Base extends AbstractBase { + private name_: string; + + toStringAbstract(): string { return 'implementation of abstract member'; }; + + get name() { + return this.name_; + } + + set name(name: string) { + this.name_ = name; + } + + // override cannot be used with optional property. + public override wasDisposed?: boolean; +} + +abstract class RejectWhenAttemptToOverrideAbstractMethod extends AbstractBase { + abstract override toStringAbstract(): string; +} + +class RejectWhenAttemptToOverrideStaticMethod extends Base { + override static toStringStatic() { return ''; }; +} + +class RejectWhenAttemptToOverridePrivateMethod extends Base { + private override toStringPrivate() { return ''; }; +} + +class RejectWhenOverrideIsRepeated extends Base { + public override override toString() { return ''; }; +} + +class RejectWhenOverridePrecedesAccessModifier extends Base { + override public toString() { return ''; }; +} + +class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + public override iDontExist() { return ''; }; +} + +class RejectWhenOverrideHasMismatchedType extends Base { + override getMeaningOfLife(): string { return 'forty-two'; }; +} + +class RejectWhenAccessorNotBothOverride extends Base { + override get name() { + return 'hardcoded value'; + } + set name(n: string) { + } +} + +/* @mhegazy: is this an appropriate test for consecutive declarations? */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + + override hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } + + public getMeaningOfLife(): number { + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { + return super.propertyIsEnumerable(prop); + } + +} + +class AcceptWhenOverrideFollowsAccessModifier extends Base { + public override toString() { return ''; }; } -class Derived extends Base { - /** @override */ - public override toString() { return "derived"; }; +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + public override getMeaningOfLife(): number { return 12; }; } From 3143818377f8fd7a12ba15c81415d713a4728210 Mon Sep 17 00:00:00 2001 From: Paul Johnston Date: Sat, 14 Jan 2017 23:30:35 -0700 Subject: [PATCH 3/9] Improves modifier checks and diagnostic messages. * Rename check{Implicit -> Augmented}PropertyMemberOverrides. * Disable augment checks in ambients contexts. * Allow override on static methods. * Add override keyword to spec.md. * Use chained diagnostics when possible. * Remove hardcoded diagnotic-related strings in checker.ts. * Split tests into separate files overrideKeyword{es5 + es6}.ts. --- doc/spec.md | 3080 ++++++++--------- src/compiler/checker.ts | 101 +- src/compiler/declarationEmitter.ts | 6 +- src/compiler/diagnosticMessages.json | 14 +- .../reference/noImplicitOverride.errors.txt | 39 +- .../baselines/reference/noImplicitOverride.js | 37 +- .../reference/overrideKeyword.errors.txt | 147 - tests/baselines/reference/overrideKeyword.js | 237 -- .../reference/overrideKeyword.symbols | 17 - .../baselines/reference/overrideKeyword.types | 19 - .../reference/overrideKeywordEs5.errors.txt | 197 ++ .../baselines/reference/overrideKeywordEs5.js | 435 +++ .../reference/overrideKeywordEs6.errors.txt | 19 + .../baselines/reference/overrideKeywordEs6.js | 61 + tests/cases/compiler/noImplicitOverride.ts | 3 +- tests/cases/compiler/overrideKeyword.ts | 89 - tests/cases/compiler/overrideKeywordEs5.ts | 126 + tests/cases/compiler/overrideKeywordEs6.ts | 15 + 18 files changed, 2520 insertions(+), 2122 deletions(-) delete mode 100644 tests/baselines/reference/overrideKeyword.errors.txt delete mode 100644 tests/baselines/reference/overrideKeyword.js delete mode 100644 tests/baselines/reference/overrideKeyword.symbols delete mode 100644 tests/baselines/reference/overrideKeyword.types create mode 100644 tests/baselines/reference/overrideKeywordEs5.errors.txt create mode 100644 tests/baselines/reference/overrideKeywordEs5.js create mode 100644 tests/baselines/reference/overrideKeywordEs6.errors.txt create mode 100644 tests/baselines/reference/overrideKeywordEs6.js delete mode 100644 tests/cases/compiler/overrideKeyword.ts create mode 100644 tests/cases/compiler/overrideKeywordEs5.ts create mode 100644 tests/cases/compiler/overrideKeywordEs6.ts diff --git a/doc/spec.md b/doc/spec.md index fa69d32105663..e9f84933c2e15 100644 --- a/doc/spec.md +++ b/doc/spec.md @@ -258,8 +258,8 @@ var i = 0; TypeScript will infer from the following function definition that the function f has return type string. ```TypeScript -function f() { - return "hello"; +function f() { + return "hello"; } ``` @@ -270,19 +270,19 @@ To benefit from this inference, a programmer can use the TypeScript language ser In this example, the programmer benefits from type inference without providing type annotations. Some beneficial tools, however, do require the programmer to provide type annotations. In TypeScript, we can express a parameter requirement as in the following code fragment. ```TypeScript -function f(s: string) { - return s; +function f(s: string) { + return s; } -f({}); // Error +f({}); // Error f("hello"); // Ok ``` This optional type annotation on the parameter 's' lets the TypeScript type checker know that the programmer expects parameter 's' to be of type 'string'. Within the body of function 'f', tools can assume 's' is of type 'string' and provide operator type checking and member completion consistent with this assumption. Tools can also signal an error on the first call to 'f', because 'f' expects a string, not an object, as its parameter. For the function 'f', the TypeScript compiler will emit the following JavaScript code: ```TypeScript -function f(s) { - return s; +function f(s) { + return s; } ``` @@ -293,7 +293,7 @@ In the JavaScript output, all type annotations have been erased. In general, Typ An ambient declaration introduces a variable into a TypeScript scope, but has zero impact on the emitted JavaScript program. Programmers can use ambient declarations to tell the TypeScript compiler that some other component will supply a variable. For example, by default the TypeScript compiler will print an error for uses of undefined variables. To add some of the common variables defined by browsers, a TypeScript programmer can use ambient declarations. The following example declares the 'document' object supplied by browsers. Because the declaration does not specify a type, the type 'any' is inferred. The type 'any' means that a tool can assume nothing about the shape or behavior of the document object. Some of the examples below will illustrate how programmers can use types to further characterize the expected behavior of an object. ```TypeScript -declare var document; +declare var document; document.title = "Hello"; // Ok because document has been declared ``` @@ -314,16 +314,16 @@ Function expressions are a powerful feature of JavaScript. They enable function TypeScript function types make it possible for programmers to express the expected *signature* of a function. A function signature is a sequence of parameter types plus a return type. The following example uses function types to express the callback signature requirements of an asynchronous voting mechanism. ```TypeScript -function vote(candidate: string, callback: (result: string) => any) { - // ... +function vote(candidate: string, callback: (result: string) => any) { + // ... } -vote("BigPig", - function(result: string) { - if (result === "BigPig") { - // ... - } - } +vote("BigPig", + function(result: string) { + if (result === "BigPig") { + // ... + } + } ); ``` @@ -342,25 +342,25 @@ Section [3.9.2](#3.9.2) provides additional information about function types. TypeScript programmers use *object types* to declare their expectations of object behavior. The following code uses an *object type literal* to specify the return type of the 'MakePoint' function. ```TypeScript -var MakePoint: () => { - x: number; y: number; +var MakePoint: () => { + x: number; y: number; }; ``` Programmers can give names to object types; we call named object types *interfaces*. For example, in the following code, an interface declares one required field (name) and one optional field (favoriteColor). ```TypeScript -interface Friend { - name: string; - favoriteColor?: string; +interface Friend { + name: string; + favoriteColor?: string; } -function add(friend: Friend) { - var name = friend.name; +function add(friend: Friend) { + var name = friend.name; } -add({ name: "Fred" }); // Ok -add({ favoriteColor: "blue" }); // Error, name required +add({ name: "Fred" }); // Ok +add({ favoriteColor: "blue" }); // Error, name required add({ name: "Jill", favoriteColor: "green" }); // Ok ``` @@ -369,27 +369,27 @@ TypeScript object types model the diversity of behaviors that a JavaScript objec The following code fragment captures a small subset of jQuery behavior, just enough to use jQuery in a simple way. ```TypeScript -interface JQuery { - text(content: string); -} - -interface JQueryStatic { - get(url: string, callback: (data: string) => any); - (query: string): JQuery; +interface JQuery { + text(content: string); +} + +interface JQueryStatic { + get(url: string, callback: (data: string) => any); + (query: string): JQuery; } declare var $: JQueryStatic; -$.get("http://mysite.org/divContent", - function (data: string) { - $("div").text(data); - } +$.get("http://mysite.org/divContent", + function (data: string) { + $("div").text(data); + } ); ``` The 'JQueryStatic' interface references another interface: 'JQuery'. This interface represents a collection of one or more DOM elements. The jQuery library can perform many operations on such a collection, but in this example the jQuery client only needs to know that it can set the text content of each jQuery element in a collection by passing a string to the 'text' method. The 'JQueryStatic' interface also contains a method, 'get', that performs an Ajax get operation on the provided URL and arranges to invoke the provided callback upon receipt of a response. -Finally, the 'JQueryStatic' interface contains a bare function signature +Finally, the 'JQueryStatic' interface contains a bare function signature ```TypeScript (query: string): JQuery; @@ -398,8 +398,8 @@ Finally, the 'JQueryStatic' interface contains a bare function signature The bare signature indicates that instances of the interface are callable. This example illustrates that TypeScript function types are just special cases of TypeScript object types. Specifically, function types are object types that contain one or more call signatures. For this reason we can write any function type as an object type literal. The following example uses both forms to describe the same type. ```TypeScript -var f: { (): string; }; -var sameType: () => string = f; // Ok +var f: { (): string; }; +var sameType: () => string = f; // Ok var nope: () => number = sameType; // Error: type mismatch ``` @@ -422,22 +422,22 @@ Section [3.3](#3.3) provides additional information about object types. Object types are compared *structurally*. For example, in the code fragment below, class 'CPoint' matches interface 'Point' because 'CPoint' has all of the required members of 'Point'. A class may optionally declare that it implements an interface, so that the compiler will check the declaration for structural compatibility. The example also illustrates that an object type can match the type inferred from an object literal, as long as the object literal supplies all of the required members. ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } -function getX(p: Point) { - return p.x; +function getX(p: Point) { + return p.x; } -class CPoint { - x: number; - y: number; - constructor(x: number, y: number) { - this.x = x; - this.y = y; - } +class CPoint { + x: number; + y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } } getX(new CPoint(0, 0)); // Ok, fields match @@ -454,8 +454,8 @@ See section [3.11](#3.11) for more information about type comparisons. Ordinarily, TypeScript type inference proceeds "bottom-up": from the leaves of an expression tree to its root. In the following example, TypeScript infers 'number' as the return type of the function 'mul' by flowing type information bottom up in the return expression. ```TypeScript -function mul(a: number, b: number) { - return a * b; +function mul(a: number, b: number) { + return a * b; } ``` @@ -464,10 +464,10 @@ For variables and parameters without a type annotation or a default value, TypeS However, in some limited contexts, inference proceeds "top-down" from the context of an expression. Where this happens, it is called contextual typing. Contextual typing helps tools provide excellent information when a programmer is using a type but may not know all of the details of the type. For example, in the jQuery example, above, the programmer supplies a function expression as the second parameter to the 'get' method. During typing of that expression, tools can assume that the type of the function expression is as given in the 'get' signature and can provide a template that includes parameter names and types. ```TypeScript -$.get("http://mysite.org/divContent", - function (data) { - $("div").text(data); // TypeScript infers data is a string - } +$.get("http://mysite.org/divContent", + function (data) { + $("div").text(data); // TypeScript infers data is a string + } ); ``` @@ -482,36 +482,36 @@ JavaScript practice has two very common design patterns: the module pattern and This section and the namespace section below will show how TypeScript emits consistent, idiomatic JavaScript when emitting ECMAScript 3 or 5 compliant code for classes and namespaces. The goal of TypeScript's translation is to emit exactly what a programmer would type when implementing a class or namespace unaided by a tool. This section will also describe how TypeScript infers a type for each class declaration. We'll start with a simple BankAccount class. ```TypeScript -class BankAccount { - balance = 0; - deposit(credit: number) { - this.balance += credit; - return this.balance; - } -} +class BankAccount { + balance = 0; + deposit(credit: number) { + this.balance += credit; + return this.balance; + } +} ``` This class generates the following JavaScript code. ```TypeScript -var BankAccount = (function () { - function BankAccount() { - this.balance = 0; - } - BankAccount.prototype.deposit = function(credit) { - this.balance += credit; - return this.balance; - }; - return BankAccount; +var BankAccount = (function () { + function BankAccount() { + this.balance = 0; + } + BankAccount.prototype.deposit = function(credit) { + this.balance += credit; + return this.balance; + }; + return BankAccount; })(); ``` This TypeScript class declaration creates a variable named 'BankAccount' whose value is the constructor function for 'BankAccount' instances. This declaration also creates an instance type of the same name. If we were to write this type as an interface it would look like the following. ```TypeScript -interface BankAccount { - balance: number; - deposit(credit: number): number; +interface BankAccount { + balance: number; + deposit(credit: number): number; } ``` @@ -526,28 +526,28 @@ The function signature is prefixed with the keyword 'new' indicating that the 'B If we want to start our bank account with an initial balance, we can add to the 'BankAccount' class a constructor declaration. ```TypeScript -class BankAccount { - balance: number; - constructor(initially: number) { - this.balance = initially; - } - deposit(credit: number) { - this.balance += credit; - return this.balance; - } +class BankAccount { + balance: number; + constructor(initially: number) { + this.balance = initially; + } + deposit(credit: number) { + this.balance += credit; + return this.balance; + } } ``` This version of the 'BankAccount' class requires us to introduce a constructor parameter and then assign it to the 'balance' field. To simplify this common case, TypeScript accepts the following shorthand syntax. ```TypeScript -class BankAccount { - constructor(public balance: number) { - } - deposit(credit: number) { - this.balance += credit; - return this.balance; - } +class BankAccount { + constructor(public balance: number) { + } + deposit(credit: number) { + this.balance += credit; + return this.balance; + } } ``` @@ -556,19 +556,19 @@ The 'public' keyword denotes that the constructor parameter is to be retained as TypeScript classes also support inheritance, as in the following example.* * ```TypeScript -class CheckingAccount extends BankAccount { - constructor(balance: number) { - super(balance); - } - writeCheck(debit: number) { - this.balance -= debit; - } +class CheckingAccount extends BankAccount { + constructor(balance: number) { + super(balance); + } + writeCheck(debit: number) { + this.balance -= debit; + } } ``` -In this example, the class 'CheckingAccount' *derives* from class 'BankAccount'. The constructor for 'CheckingAccount' calls the constructor for class 'BankAccount' using the 'super' keyword. In the emitted JavaScript code, the prototype of 'CheckingAccount' will chain to the prototype of 'BankAccount'. +In this example, the class 'CheckingAccount' *derives* from class 'BankAccount'. The constructor for 'CheckingAccount' calls the constructor for class 'BankAccount' using the 'super' keyword. In the emitted JavaScript code, the prototype of 'CheckingAccount' will chain to the prototype of 'BankAccount'. -TypeScript classes may also specify static members. Static class members become properties of the class constructor. +TypeScript classes may also specify static members. Static class members become properties of the class constructor. Section [8](#8) provides additional information about classes. @@ -577,16 +577,16 @@ Section [8](#8) provides additional information about classes. TypeScript enables programmers to summarize a set of numeric constants as an *enum type*. The example below creates an enum type to represent operators in a calculator application. ```TypeScript -const enum Operator { - ADD, - DIV, - MUL, - SUB +const enum Operator { + ADD, + DIV, + MUL, + SUB } -function compute(op: Operator, a: number, b: number) { - console.log("the operator is" + Operator[op]); - // ... +function compute(op: Operator, a: number, b: number) { + console.log("the operator is" + Operator[op]); + // ... } ``` @@ -597,28 +597,28 @@ When enums are declared with the `const` modifier, the TypeScript compiler will For example, the 'compute' function could contain a switch statement like the following. ```TypeScript -switch (op) { - case Operator.ADD: - // execute add - break; - case Operator.DIV: - // execute div - break; - // ... +switch (op) { + case Operator.ADD: + // execute add + break; + case Operator.DIV: + // execute div + break; + // ... } ``` For this switch statement, the compiler will generate the following code. ```TypeScript -switch (op) { - case 0 /* Operator.ADD */: - // execute add - break; - case 1 /* Operator.DIV */: - // execute div - break; - // ... +switch (op) { + case 0 /* Operator.ADD */: + // execute add + break; + case 1 /* Operator.DIV */: + // execute div + break; + // ... } ``` @@ -635,7 +635,7 @@ JavaScript programming interfaces often include functions whose behavior is disc The following code fragment uses this feature. Because the 'span' variable is inferred to have the type 'HTMLSpanElement', the code can reference without static error the 'isMultiline' property of 'span'. ```TypeScript -var span = document.createElement("span"); +var span = document.createElement("span"); span.isMultiLine = false; // OK: HTMLSpanElement has isMultiline property ``` @@ -652,10 +652,10 @@ Like overloading on string parameters, *generic types* make it easier for TypeSc To illustrate this, let's take a look at part of the TypeScript interface for the built-in JavaScript array type. You can find this interface in the 'lib.d.ts' file that accompanies a TypeScript distribution. ```TypeScript -interface Array { - reverse(): T[]; - sort(compareFn?: (a: T, b: T) => number): T[]; - // ... +interface Array { + reverse(): T[]; + sort(compareFn?: (a: T, b: T) => number): T[]; + // ... } ``` @@ -672,9 +672,9 @@ The map method, invoked on an array 'a' with element type 'T', will apply functi The TypeScript compiler can often infer generic method parameters, making it unnecessary for the programmer to explicitly provide them. In the following example, the compiler infers that parameter 'U' of the map method has type 'string', because the function passed to map returns a string. ```TypeScript -function numberToString(a: number[]) { - var stringArray = a.map(v => v.toString()); - return stringArray; +function numberToString(a: number[]) { + var stringArray = a.map(v => v.toString()); + return stringArray; } ``` @@ -683,27 +683,27 @@ The compiler infers in this example that the 'numberToString' function returns a In TypeScript, classes can also have type parameters. The following code declares a class that implements a linked list of items of type 'T'. This code illustrates how programmers can *constrain* type parameters to extend a specific type. In this case, the items on the list must extend the type 'NamedItem'. This enables the programmer to implement the 'log' function, which logs the name of the item. ```TypeScript -interface NamedItem { - name: string; +interface NamedItem { + name: string; } -class List { +class List { next: List = null; - constructor(public item: T) { + constructor(public item: T) { } - insertAfter(item: T) { - var temp = this.next; - this.next = new List(item); - this.next.next = temp; + insertAfter(item: T) { + var temp = this.next; + this.next = new List(item); + this.next.next = temp; } - log() { - console.log(this.item.name); + log() { + console.log(this.item.name); } - // ... + // ... } ``` @@ -713,17 +713,17 @@ Section [3.7](#3.7) provides further information about generic types. Classes and interfaces support large-scale JavaScript development by providing a mechanism for describing how to use a software component that can be separated from that component's implementation. TypeScript enforces *encapsulation* of implementation in classes at design time (by restricting use of private and protected members), but cannot enforce encapsulation at runtime because all object properties are accessible at runtime. Future versions of JavaScript may provide *private names* which would enable runtime enforcement of private and protected members. -In JavaScript, a very common way to enforce encapsulation at runtime is to use the module pattern: encapsulate private fields and methods using closure variables. The module pattern is a natural way to provide organizational structure and dynamic loading options by drawing a boundary around a software component. The module pattern can also provide the ability to introduce namespaces, avoiding use of the global namespace for most software components. +In JavaScript, a very common way to enforce encapsulation at runtime is to use the module pattern: encapsulate private fields and methods using closure variables. The module pattern is a natural way to provide organizational structure and dynamic loading options by drawing a boundary around a software component. The module pattern can also provide the ability to introduce namespaces, avoiding use of the global namespace for most software components. The following example illustrates the JavaScript module pattern. ```TypeScript -(function(exports) { - var key = generateSecretKey(); - function sendMessage(message) { - sendSecureMessage(message, key); - } - exports.sendMessage = sendMessage; +(function(exports) { + var key = generateSecretKey(); + function sendMessage(message) { + sendSecureMessage(message, key); + } + exports.sendMessage = sendMessage; })(MessageModule); ``` @@ -736,22 +736,22 @@ TypeScript namespaces provide a mechanism for succinctly expressing the module p The following example shows the definition and use of a simple namespace. ```TypeScript -namespace M { - var s = "hello"; - export function f() { - return s; - } +namespace M { + var s = "hello"; + export function f() { + return s; + } } -M.f(); +M.f(); M.s; // Error, s is not exported ``` In this example, variable 's' is a private feature of the namespace, but function 'f' is exported from the namespace and accessible to code outside of the namespace. If we were to describe the effect of namespace 'M' in terms of interfaces and variables, we would write ```TypeScript -interface M { - f(): string; +interface M { + f(): string; } var M: M; @@ -762,13 +762,13 @@ The interface 'M' summarizes the externally visible behavior of namespace 'M'. I The TypeScript compiler emits the following JavaScript code for the namespace: ```TypeScript -var M; -(function(M) { - var s = "hello"; - function f() { - return s; - } - M.f = f; +var M; +(function(M) { + var s = "hello"; + function f() { + return s; + } + M.f = f; })(M || (M = {})); ``` @@ -788,10 +788,10 @@ The remainder of this document is the formal specification of the TypeScript pro The syntactic grammar added by TypeScript language is specified throughout this document using the existing conventions and production names of the ECMAScript grammar. In places where TypeScript augments an existing grammar production it is so noted. For example: -  *Declaration:* *( Modified )* -   … -   *InterfaceDeclaration* -   *TypeAliasDeclaration* +  *Declaration:* *( Modified )* +   … +   *InterfaceDeclaration* +   *TypeAliasDeclaration*    *EnumDeclaration* The '*( Modified )*' annotation indicates that an existing grammar production is being replaced, and the '…' references the contents of the original grammar production. @@ -814,55 +814,56 @@ Most commonly, names are written to conform with the *Identifier* production, wh The following keywords are reserved and cannot be used as an *Identifier*: ```TypeScript -break case catch class -const continue debugger default -delete do else enum -export extends false finally -for function if import -in instanceof new null -return super switch this -throw true try typeof +break case catch class +const continue debugger default +delete do else enum +export extends false finally +for function if import +in instanceof new null +return super switch this +throw true try typeof var void while with ``` The following keywords cannot be used as identifiers in strict mode code, but are otherwise not restricted: ```TypeScript -implements interface let package -private protected public static +implements interface let package +private protected public static yield ``` The following keywords cannot be used as user defined type names, but are otherwise not restricted: ```TypeScript -any boolean number string +any boolean number string symbol ``` The following keywords have special meaning in certain contexts, but are valid identifiers: ```TypeScript -abstract as async await -constructor declare from get -is module namespace of -require set type +abstract as async await +constructor declare from get +is module namespace of +override readonly require set +type ``` ### 2.2.2 Property Names The *PropertyName* production from the ECMAScript grammar is reproduced below: -  *PropertyName:* -   *LiteralPropertyName* +  *PropertyName:* +   *LiteralPropertyName*    *ComputedPropertyName* -  *LiteralPropertyName:* -   *IdentifierName* -   *StringLiteral* +  *LiteralPropertyName:* +   *IdentifierName* +   *StringLiteral*    *NumericLiteral* -  *ComputedPropertyName:* +  *ComputedPropertyName:*    `[` *AssignmentExpression* `]` A property name can be any identifier (including a reserved word), a string literal, a numeric literal, or a computed property name. String literals may be used to give properties names that are not valid identifiers, such as names containing blanks. Numeric literal property names are equivalent to string literal property names with the string representation of the numeric literal, as defined in the ECMAScript specification. @@ -882,8 +883,8 @@ In a *PropertyName* that specifies a *ComputedPropertyName*, the computed proper Below is an example of an interface that declares a property with a well-known symbol name: ```TypeScript -interface Iterable { - [Symbol.iterator](): Iterator; +interface Iterable { + [Symbol.iterator](): Iterator; } ``` @@ -898,8 +899,8 @@ var X: string; // Value named X type X = number; // Type named X -namespace X { // Namespace named X - type Y = string; +namespace X { // Namespace named X + type Y = string; } ``` @@ -908,7 +909,7 @@ A name that denotes a value has an associated type (section [3](#3)) and can be When a name with multiple meanings is referenced, the context in which the reference occurs determines the meaning. For example: ```TypeScript -var n: X; // X references type +var n: X; // X references type var s: X.Y = X; // First X references namespace, second X references value ``` @@ -926,12 +927,12 @@ Declarations introduce the following meanings for the name they declare: Below are some examples of declarations that introduce multiple meanings for a name: ```TypeScript -class C { // Value and type named C - x: string; +class C { // Value and type named C + x: string; } -namespace N { // Value and namespace named N - export var x: string; +namespace N { // Value and namespace named N + export var x: string; } ``` @@ -970,9 +971,9 @@ Interfaces, enums, and namespaces are "open ended," meaning that interface, enum Instance and static members in a class are in separate declaration spaces. Thus the following is permitted: ```TypeScript -class C { - x: number; // Instance member - static x: string; // Static member +class C { + x: number; // Instance member + static x: string; // Static member } ``` @@ -1008,17 +1009,17 @@ Note that class and interface members are never directly in scope—they can onl As the rules above imply, locally declared entities in a namespace are closer in scope than exported entities declared in other namespace declarations for the same namespace. For example: ```TypeScript -var x = 1; -namespace M { - export var x = 2; - console.log(x); // 2 -} -namespace M { - console.log(x); // 2 -} -namespace M { - var x = 3; - console.log(x); // 3 +var x = 1; +namespace M { + export var x = 2; + console.log(x); // 2 +} +namespace M { + console.log(x); // 2 +} +namespace M { + var x = 3; + console.log(x); // 3 } ``` @@ -1061,12 +1062,12 @@ The Any type is a supertype of all types, and is assignable to and from all type Some examples: ```TypeScript -var x: any; // Explicitly typed -var y; // Same as y: any +var x: any; // Explicitly typed +var y; // Same as y: any var z: { a; b; }; // Same as z: { a: any; b: any; } -function f(x) { // Same as f(x: any): void - console.log(x); +function f(x) { // Same as f(x: any): void + console.log(x); } ``` @@ -1085,9 +1086,9 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var x: number; // Explicitly typed -var y = 0; // Same as y: number = 0 -var z = 123.456; // Same as z: number = 123.456 +var x: number; // Explicitly typed +var y = 0; // Same as y: number = 0 +var z = 123.456; // Same as z: number = 123.456 var s = z.toFixed(2); // Property of Number interface ``` @@ -1102,8 +1103,8 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var b: boolean; // Explicitly typed -var yes = true; // Same as yes: boolean = true +var b: boolean; // Explicitly typed +var yes = true; // Same as yes: boolean = true var no = false; // Same as no: boolean = false ``` @@ -1118,9 +1119,9 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var s: string; // Explicitly typed -var empty = ""; // Same as empty: string = "" -var abc = 'abc'; // Same as abc: string = "abc" +var s: string; // Explicitly typed +var empty = ""; // Same as empty: string = "" +var abc = 'abc'; // Same as abc: string = "abc" var c = abc.charAt(2); // Property of String interface ``` @@ -1135,9 +1136,9 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var secretKey = Symbol(); -var obj = {}; -obj[secretKey] = "secret message"; // Use symbol as property key +var secretKey = Symbol(); +var obj = {}; +obj[secretKey] = "secret message"; // Use symbol as property key obj[Symbol.toStringTag] = "test"; // Use of well-known symbol ``` @@ -1160,8 +1161,8 @@ The Null type is a subtype of all types, except the Undefined type. This means t Some examples: ```TypeScript -var n: number = null; // Primitives can be null -var x = null; // Same as x: any = null +var n: number = null; // Primitives can be null +var x = null; // Same as x: any = null var e: Null; // Error, can't reference Null type ``` @@ -1176,8 +1177,8 @@ The undefined type is a subtype of all types. This means that `undefined` is con Some examples: ```TypeScript -var n: number; // Same as n: number = undefined -var x = undefined; // Same as x: any = undefined +var n: number; // Same as n: number = undefined +var x = undefined; // Same as x: any = undefined var e: Undefined; // Error, can't reference Undefined type ``` @@ -1223,10 +1224,10 @@ Type references (section [3.8.2](#3.8.2)) to class and interface types are class The declaration of the 'Array' interface includes a property 'length' and a numeric index signature for the element type, along with other members: ```TypeScript -interface Array { - length: number; - [x: number]: T; - // Other members +interface Array { + length: number; + [x: number]: T; + // Other members } ``` @@ -1249,11 +1250,11 @@ A type is said to be an ***array-like type*** if it is assignable (section [3.11 combines the set of properties ```TypeScript -{ - 0: T0; - 1: T1; - ... - n: Tn; +{ + 0: T0; + 1: T1; + ... + n: Tn; } ``` @@ -1262,10 +1263,10 @@ with the members of an array type whose element type is the union type (section Array literals (section [4.6](#4.6)) may be used to create values of tuple types. For example: ```TypeScript -var t: [number, string] = [3, "three"]; -var n = t[0]; // Type of n is number -var s = t[1]; // Type of s is string -var i: number; +var t: [number, string] = [3, "three"]; +var n = t[0]; // Type of n is number +var s = t[1]; // Type of s is string +var i: number; var x = t[i]; // Type of x is number | string ``` @@ -1326,12 +1327,12 @@ Type guards (section [4.24](#4.24)) may be used to narrow a union type to a more In the example ```TypeScript -var x: string | number; -var test: boolean; -x = "hello"; // Ok -x = 42; // Ok -x = test; // Error, boolean not assignable -x = test ? 5 : "five"; // Ok +var x: string | number; +var test: boolean; +x = "hello"; // Ok +x = 42; // Ok +x = test; // Error, boolean not assignable +x = test ? 5 : "five"; // Ok x = test ? 0 : false; // Error, number | boolean not assignable ``` @@ -1344,20 +1345,20 @@ var n = typeof x === "string" ? x.length : x; // Type of n is number For purposes of property access and function calls, the apparent members (section [3.11.1](#3.11.1)) of a union type are those that are present in every one of its constituent types, with types that are unions of the respective apparent members in the constituent types. The following example illustrates the merging of member types that occurs when union types are created from object types. ```TypeScript -interface A { - a: string; - b: number; +interface A { + a: string; + b: number; } -interface B { - a: number; - b: number; - c: number; +interface B { + a: number; + b: number; + c: number; } -var x: A | B; -var a = x.a; // a has type string | number -var b = x.b; // b has type number +var x: A | B; +var a = x.a; // a has type string | number +var b = x.b; // b has type number var c = x.c; // Error, no property c in union type ``` @@ -1384,36 +1385,36 @@ Similarly, intersection types have the following assignability relationships: For purposes of property access and function calls, the apparent members (section [3.11.1](#3.11.1)) of an intersection type are those that are present in one or more of its constituent types, with types that are intersections of the respective apparent members in the constituent types. The following examples illustrate the merging of member types that occurs when intersection types are created from object types. ```TypeScript -interface A { a: number } +interface A { a: number } interface B { b: number } -var ab: A & B = { a: 1, b: 1 }; -var a: A = ab; // A & B assignable to A +var ab: A & B = { a: 1, b: 1 }; +var a: A = ab; // A & B assignable to A var b: B = ab; // A & B assignable to B -interface X { p: A } +interface X { p: A } interface Y { p: B } var xy: X & Y = { p: ab }; // X & Y has property p of type A & B -type F1 = (a: string, b: string) => void; +type F1 = (a: string, b: string) => void; type F2 = (a: number, b: number) => void; -var f: F1 & F2 = (a: string | number, b: string | number) => { }; -f("hello", "world"); // Ok -f(1, 2); // Ok +var f: F1 & F2 = (a: string | number, b: string | number) => { }; +f("hello", "world"); // Ok +f(1, 2); // Ok f(1, "test"); // Error ``` The union and intersection type operators can be applied to type parameters. This capability can for example be used to model functions that merge objects: ```TypeScript -function extend(first: T, second: U): T & U { - // Extend first with properties of second +function extend(first: T, second: U): T & U { + // Extend first with properties of second } -var x = extend({ a: "hello" }, { b: 42 }); -var s = x.a; +var x = extend({ a: "hello" }, { b: 42 }); +var s = x.a; var n = x.b; ``` @@ -1429,17 +1430,17 @@ Since a type parameter represents a multitude of different type arguments, type Class, interface, type alias, and function declarations may optionally include lists of type parameters enclosed in < and > brackets. Type parameters are also permitted in call signatures of object, function, and constructor type literals. -  *TypeParameters:* +  *TypeParameters:*    `<` *TypeParameterList* `>` -  *TypeParameterList:* -   *TypeParameter* +  *TypeParameterList:* +   *TypeParameter*    *TypeParameterList* `,` *TypeParameter* -  *TypeParameter:* +  *TypeParameter:*    *BindingIdentifier* *Constraintopt* -  *Constraint:* +  *Constraint:*    `extends` *Type* Type parameter names must be unique. A compile-time error occurs if two or more type parameters in the same *TypeParameterList* have the same name. @@ -1476,14 +1477,14 @@ interface B { } A type reference (section [3.8.2](#3.8.2)) to a generic type must include a list of type arguments enclosed in angle brackets and separated by commas. Similarly, a call (section [4.15](#4.15)) to a generic function may explicitly include a type argument list instead of relying on type inference. -  *TypeArguments:* +  *TypeArguments:*    `<` *TypeArgumentList* `>` -  *TypeArgumentList:* -   *TypeArgument* +  *TypeArgumentList:* +   *TypeArgument*    *TypeArgumentList* `,` *TypeArgument* -  *TypeArgument:* +  *TypeArgument:*    *Type* Type arguments correspond one-to-one with type parameters of the generic type or function being referenced. A type argument list is required to specify exactly one type argument for each corresponding type parameter, and each type argument for a constrained type parameter is required to ***satisfy*** the constraint of that type parameter. A type argument satisfies a type parameter constraint if the type argument is assignable to (section [3.11.4](#3.11.4)) the constraint type once type arguments are substituted for type parameters. @@ -1505,19 +1506,19 @@ Every class and interface has a ***this-type*** that represents the actual type Classes and interfaces support inheritance and therefore the instance represented by `this` in a method isn't necessarily an instance of the containing class—it may in fact be an instance of a derived class or interface. To model this relationship, the this-type of a class or interface is classified as a type parameter. Unlike other type parameters, it is not possible to explicitly pass a type argument for a this-type. Instead, in a type reference to a class or interface type, the type reference *itself* is implicitly passed as a type argument for the this-type. For example: ```TypeScript -class A { - foo() { - return this; - } +class A { + foo() { + return this; + } } -class B extends A { - bar() { - return this; - } +class B extends A { + bar() { + return this; + } } -let b: B; +let b: B; let x = b.foo().bar(); // Fluent pattern works, type of x is B ``` @@ -1557,37 +1558,37 @@ is indistinguishable from the type Types are specified either by referencing their keyword or name, or by writing object type literals, array type literals, tuple type literals, function type literals, constructor type literals, or type queries. -  *Type:* -   *UnionOrIntersectionOrPrimaryType* -   *FunctionType* +  *Type:* +   *UnionOrIntersectionOrPrimaryType* +   *FunctionType*    *ConstructorType* -  *UnionOrIntersectionOrPrimaryType:* -   *UnionType* +  *UnionOrIntersectionOrPrimaryType:* +   *UnionType*    *IntersectionOrPrimaryType* -  *IntersectionOrPrimaryType:* -   *IntersectionType* +  *IntersectionOrPrimaryType:* +   *IntersectionType*    *PrimaryType* -  *PrimaryType:* -   *ParenthesizedType* -   *PredefinedType* -   *TypeReference* -   *ObjectType* -   *ArrayType* -   *TupleType* -   *TypeQuery* +  *PrimaryType:* +   *ParenthesizedType* +   *PredefinedType* +   *TypeReference* +   *ObjectType* +   *ArrayType* +   *TupleType* +   *TypeQuery*    *ThisType* -  *ParenthesizedType:* +  *ParenthesizedType:*    `(` *Type* `)` Parentheses are required around union, intersection, function, or constructor types when they are used as array element types; around union, function, or constructor types in intersection types; and around function or constructor types in union types. For example: ```TypeScript -(string | number)[] -((x: string) => string) | ((x: number) => number) +(string | number)[] +((x: string) => string) | ((x: number) => number) (A | B) & (C | D) ``` @@ -1597,12 +1598,12 @@ The different forms of type notations are described in the following sections. The `any`, `number`, `boolean`, `string`, `symbol` and `void` keywords reference the Any type and the Number, Boolean, String, Symbol, and Void primitive types respectively. -  *PredefinedType:* -   `any` -   `number` -   `boolean` -   `string` -   `symbol` +  *PredefinedType:* +   `any` +   `number` +   `boolean` +   `string` +   `symbol`    `void` The predefined type keywords are reserved and cannot be used as names of user defined types. @@ -1611,15 +1612,15 @@ The predefined type keywords are reserved and cannot be used as names of user de A type reference references a named type or type parameter through its name and, in the case of a generic type, supplies a type argument list. -  *TypeReference:* +  *TypeReference:*    *TypeName* *[no LineTerminator here]* *TypeArgumentsopt* -  *TypeName:* -   *IdentifierReference* +  *TypeName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* -  *NamespaceName:* -   *IdentifierReference* +  *NamespaceName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* A *TypeReference* consists of a *TypeName* that a references a named type or type parameter. A reference to a generic type must be followed by a list of *TypeArguments* (section [3.6.2](#3.6.2)). @@ -1643,17 +1644,17 @@ interface B extends A { b: string; } interface C extends B { c: string; } -interface G { - x: T; - y: U; +interface G { + x: T; + y: U; } -var v1: G; // Ok -var v2: G<{ a: string }, C>; // Ok, equivalent to G -var v3: G; // Error, A not valid argument for U -var v4: G, C>; // Ok -var v5: G; // Ok -var v6: G; // Error, wrong number of arguments +var v1: G; // Ok +var v2: G<{ a: string }, C>; // Ok, equivalent to G +var v3: G; // Error, A not valid argument for U +var v4: G, C>; // Ok +var v5: G; // Ok +var v6: G; // Error, wrong number of arguments var v7: G; // Error, no arguments ``` @@ -1662,9 +1663,9 @@ A type argument is simply a *Type* and may itself be a type reference to a gener As described in section [3.7](#3.7), a type reference to a generic type *G* designates a type wherein all occurrences of *G*'s type parameters have been replaced with the actual type arguments supplied in the type reference. For example, the declaration of 'v1' above is equivalent to: ```TypeScript -var v1: { - x: { a: string; } - y: { a: string; b: string; c: string }; +var v1: { + x: { a: string; } + y: { a: string; b: string; c: string }; }; ``` @@ -1672,23 +1673,23 @@ var v1: { An object type literal defines an object type by specifying the set of members that are statically considered to be present in instances of the type. Object type literals can be given names using interface declarations but are otherwise anonymous. -  *ObjectType:* +  *ObjectType:*    `{` *TypeBodyopt* `}` -  *TypeBody:* -   *TypeMemberList* `;`*opt* +  *TypeBody:* +   *TypeMemberList* `;`*opt*    *TypeMemberList* `,`*opt* -  *TypeMemberList:* -   *TypeMember* -   *TypeMemberList* `;` *TypeMember* +  *TypeMemberList:* +   *TypeMember* +   *TypeMemberList* `;` *TypeMember*    *TypeMemberList* `,` *TypeMember* -  *TypeMember:* -   *PropertySignature* -   *CallSignature* -   *ConstructSignature* -   *IndexSignature* +  *TypeMember:* +   *PropertySignature* +   *CallSignature* +   *ConstructSignature* +   *IndexSignature*    *MethodSignature* The members of an object type literal are specified as a combination of property, call, construct, index, and method signatures. Object type members are described in section [3.9](#3.9). @@ -1697,7 +1698,7 @@ The members of an object type literal are specified as a combination of property An array type literal is written as an element type followed by an open and close square bracket. -  *ArrayType:* +  *ArrayType:*    *PrimaryType* *[no LineTerminator here]* `[` `]` An array type literal references an array type (section [3.3.2](#3.3.2)) with the given element type. An array type literal is simply shorthand notation for a reference to the generic interface type 'Array' in the global namespace with the element type as a type argument. @@ -1705,14 +1706,14 @@ An array type literal references an array type (section [3.3.2](#3.3.2)) with th When union, intersection, function, or constructor types are used as array element types they must be enclosed in parentheses. For example: ```TypeScript -(string | number)[] +(string | number)[] (() => string))[] ``` Alternatively, array types can be written using the 'Array<T>' notation. For example, the types above are equivalent to ```TypeScript -Array +Array Array<() => string> ``` @@ -1720,14 +1721,14 @@ Array<() => string> A tuple type literal is written as a sequence of element types, separated by commas and enclosed in square brackets. -  *TupleType:* +  *TupleType:*    `[` *TupleElementTypes* `]` -  *TupleElementTypes:* -   *TupleElementType* +  *TupleElementTypes:* +   *TupleElementType*    *TupleElementTypes* `,` *TupleElementType* -  *TupleElementType:* +  *TupleElementType:*    *Type* A tuple type literal references a tuple type (section [3.3.3](#3.3.3)). @@ -1736,7 +1737,7 @@ A tuple type literal references a tuple type (section [3.3.3](#3.3.3)). A union type literal is written as a sequence of types separated by vertical bars. -  *UnionType:* +  *UnionType:*    *UnionOrIntersectionOrPrimaryType* `|` *IntersectionOrPrimaryType* A union type literal references a union type (section [3.4](#3.4)). @@ -1745,7 +1746,7 @@ A union type literal references a union type (section [3.4](#3.4)). An intersection type literal is written as a sequence of types separated by ampersands. -  *IntersectionType:* +  *IntersectionType:*    *IntersectionOrPrimaryType* `&` *PrimaryType* An intersection type literal references an intersection type (section [3.5](#3.5)). @@ -1754,7 +1755,7 @@ An intersection type literal references an intersection type (section [3.5](#3.5 A function type literal specifies the type parameters, regular parameters, and return type of a call signature. -  *FunctionType:* +  *FunctionType:*    *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* A function type literal is shorthand for an object type containing a single call signature. Specifically, a function type literal of the form @@ -1775,7 +1776,7 @@ Note that function types with multiple call or construct signatures cannot be wr A constructor type literal specifies the type parameters, regular parameters, and return type of a construct signature. -  *ConstructorType:* +  *ConstructorType:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* A constructor type literal is shorthand for an object type containing a single construct signature. Specifically, a constructor type literal of the form @@ -1796,11 +1797,11 @@ Note that constructor types with multiple construct signatures cannot be written A type query obtains the type of an expression. -  *TypeQuery:* +  *TypeQuery:*    `typeof` *TypeQueryExpression* -  *TypeQueryExpression:* -   *IdentifierReference* +  *TypeQueryExpression:* +   *IdentifierReference*    *TypeQueryExpression* `.` *IdentifierName* A type query consists of the keyword `typeof` followed by an expression. The expression is restricted to a single identifier or a sequence of identifiers separated by periods. The expression is processed as an identifier expression (section [4.3](#4.3)) or property access expression (section [4.13](#4.13)), the widened type (section [3.12](#3.12)) of which becomes the result. Similar to other static typing constructs, type queries are erased from the generated JavaScript code and add no run-time overhead. @@ -1808,7 +1809,7 @@ A type query consists of the keyword `typeof` followed by an expression. The exp Type queries are useful for capturing anonymous types that are generated by various constructs such as object literals, function declarations, and namespace declarations. For example: ```TypeScript -var a = { x: 10, y: 20 }; +var a = { x: 10, y: 20 }; var b: typeof a; ``` @@ -1817,16 +1818,16 @@ Above, 'b' is given the same type as 'a', namely `{ x: number; y: number; }`. If a declaration includes a type annotation that references the entity being declared through a circular path of type queries or type references containing type queries, the resulting type is the Any type. For example, all of the following variables are given the type Any: ```TypeScript -var c: typeof c; -var d: typeof e; -var e: typeof d; +var c: typeof c; +var d: typeof e; +var e: typeof d; var f: Array; ``` However, if a circular path of type queries includes at least one *ObjectType*, *FunctionType* or *ConstructorType*, the construct denotes a recursive type: ```TypeScript -var g: { x: typeof g; }; +var g: { x: typeof g; }; var h: () => typeof h; ``` @@ -1836,7 +1837,7 @@ Here, 'g' and 'g.x' have the same recursive type, and likewise 'h' and 'h()' hav The `this` keyword is used to reference the this-type (section [3.6.3](#3.6.3)) of a class or interface. -  *ThisType:* +  *ThisType:*    `this` The meaning of a *ThisType* depends on the closest enclosing *FunctionDeclaration*, *FunctionExpression*, *PropertyDefinition*, *ClassElement*, or *TypeMember*, known as the root declaration of the *ThisType*, as follows: @@ -1848,10 +1849,10 @@ The meaning of a *ThisType* depends on the closest enclosing *FunctionDeclaratio Note that in order to avoid ambiguities it is not possible to reference the this-type of a class or interface in a nested object type literal. In the example ```TypeScript -interface ListItem { - getHead(): this; - getTail(): this; - getHeadAndTail(): { head: this, tail: this }; // Error +interface ListItem { + getHead(): this; + getTail(): this; + getHeadAndTail(): { head: this, tail: this }; // Error } ``` @@ -1860,25 +1861,25 @@ the `this` references on the last line are in error because their root declarati ```TypeScript type HeadAndTail = { head: T, tail: T }; -interface ListItem { - getHead(): this; - getTail(): this; - getHeadAndTail(): HeadAndTail; +interface ListItem { + getHead(): this; + getTail(): this; + getHeadAndTail(): HeadAndTail; } ``` ## 3.9 Specifying Members -The members of an object type literal (section [3.8.3](#3.8.3)) are specified as a combination of property, call, construct, index, and method signatures. +The members of an object type literal (section [3.8.3](#3.8.3)) are specified as a combination of property, call, construct, index, and method signatures. ### 3.9.1 Property Signatures A property signature declares the name and type of a property member. -  *PropertySignature:* +  *PropertySignature:*    *PropertyName* `?`*opt* *TypeAnnotationopt* -  *TypeAnnotation:* +  *TypeAnnotation:*    `:` *Type* The *PropertyName* ([2.2.2](#2.2.2)) of a property signature must be unique within its containing type, and must denote a well-known symbol if it is a computed property name ([2.2.3](#2.2.3)). If the property name is followed by a question mark, the property is optional. Otherwise, the property is required. @@ -1889,7 +1890,7 @@ If a property signature omits a *TypeAnnotation*, the Any type is assumed. A call signature defines the type parameters, parameter list, and return type associated with applying a call operation (section [4.15](#4.15)) to an instance of the containing type. A type may ***overload*** call operations by defining multiple different call signatures. -  *CallSignature:* +  *CallSignature:*    *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* A call signature that includes *TypeParameters* (section [3.6.1](#3.6.1)) is called a ***generic call signature***. Conversely, a call signature with no *TypeParameters* is called a non-generic call signature. @@ -1936,42 +1937,42 @@ A function taking an array of one type and a function argument, returning an arr A signature's parameter list consists of zero or more required parameters, followed by zero or more optional parameters, finally followed by an optional rest parameter. -  *ParameterList:* -   *RequiredParameterList* -   *OptionalParameterList* -   *RestParameter* -   *RequiredParameterList* `,` *OptionalParameterList* -   *RequiredParameterList* `,` *RestParameter* -   *OptionalParameterList* `,` *RestParameter* +  *ParameterList:* +   *RequiredParameterList* +   *OptionalParameterList* +   *RestParameter* +   *RequiredParameterList* `,` *OptionalParameterList* +   *RequiredParameterList* `,` *RestParameter* +   *OptionalParameterList* `,` *RestParameter*    *RequiredParameterList* `,` *OptionalParameterList* `,` *RestParameter* -  *RequiredParameterList:* -   *RequiredParameter* +  *RequiredParameterList:* +   *RequiredParameter*    *RequiredParameterList* `,` *RequiredParameter* -  *RequiredParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* +  *RequiredParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt*    *BindingIdentifier* `:` *StringLiteral* -  *AccessibilityModifier:* -   `public` -   `private` +  *AccessibilityModifier:* +   `public` +   `private`    `protected` -  *BindingIdentifierOrPattern:* -   *BindingIdentifier* +  *BindingIdentifierOrPattern:* +   *BindingIdentifier*    *BindingPattern* -  *OptionalParameterList:* -   *OptionalParameter* +  *OptionalParameterList:* +   *OptionalParameter*    *OptionalParameterList* `,` *OptionalParameter* -  *OptionalParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer* +  *OptionalParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer*    *BindingIdentifier* `?` `:` *StringLiteral* -  *RestParameter:* +  *RestParameter:*    `...` *BindingIdentifier* *TypeAnnotationopt* A parameter declaration may specify either an identifier or a binding pattern ([5.2.2](#5.2.2)). The identifiers specified in parameter declarations and binding patterns in a parameter list must be unique within that parameter list. @@ -2009,11 +2010,11 @@ When a call signature with no return type annotation occurs in a context that ha When a parameter type annotation specifies a string literal type (section [3.2.9](#3.2.9)), the containing signature is considered a specialized signature. Specialized signatures are used to express patterns where specific string values for some parameters cause the types of other parameters or the function result to become further specialized. For example, the declaration ```TypeScript -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; - createElement(tagName: string): HTMLElement; +interface Document { + createElement(tagName: "div"): HTMLDivElement; + createElement(tagName: "span"): HTMLSpanElement; + createElement(tagName: "canvas"): HTMLCanvasElement; + createElement(tagName: string): HTMLElement; } ``` @@ -2027,7 +2028,7 @@ Every specialized call or construct signature in an object type must be assignab A construct signature defines the parameter list and return type associated with applying the `new` operator (section [4.14](#4.14)) to an instance of the containing type. A type may overload `new` operations by defining multiple construct signatures with different parameter lists. -  *ConstructSignature:* +  *ConstructSignature:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* The type parameters, parameter list, and return type of a construct signature are subject to the same rules as a call signature. @@ -2038,8 +2039,8 @@ A type containing construct signatures is said to be a ***constructor type***. An index signature defines a type constraint for properties in the containing type. -  *IndexSignature:* -   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation* +  *IndexSignature:* +   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation*    `[` *BindingIdentifier* `:` `number` `]` *TypeAnnotation* There are two kinds of index signatures: @@ -2057,7 +2058,7 @@ Index signatures affect the determination of the type that results from applying A method signature is shorthand for declaring a property of a function type. -  *MethodSignature:* +  *MethodSignature:*    *PropertyName* `?`*opt* *CallSignature* If the *PropertyName* is a computed property name ([2.2.3](#2.2.3)), it must specify a well-known symbol. If the *PropertyName* is followed by a question mark, the property is optional. Otherwise, the property is required. Only object type literals and interfaces can declare optional properties. @@ -2077,41 +2078,41 @@ f : { < T1, T2, ... > ( p1, p2, ... ) : R } A literal type may ***overload*** a method by declaring multiple method signatures with the same name but differing parameter lists. Overloads must either all be required (question mark omitted) or all be optional (question mark included). A set of overloaded method signatures correspond to a declaration of a single property with a type composed from an equivalent set of call signatures. Specifically ```TypeScript -f < T1, T2, ... > ( p1, p2, ... ) : R ; -f < U1, U2, ... > ( q1, q2, ... ) : S ; +f < T1, T2, ... > ( p1, p2, ... ) : R ; +f < U1, U2, ... > ( q1, q2, ... ) : S ; ... ``` is equivalent to ```TypeScript -f : { - < T1, T2, ... > ( p1, p2, ... ) : R ; - < U1, U2, ... > ( q1, q2, ... ) : S ; - ... +f : { + < T1, T2, ... > ( p1, p2, ... ) : R ; + < U1, U2, ... > ( q1, q2, ... ) : S ; + ... } ; ``` In the following example of an object type ```TypeScript -{ - func1(x: number): number; // Method signature - func2: (x: number) => number; // Function type literal - func3: { (x: number): number }; // Object type literal +{ + func1(x: number): number; // Method signature + func2: (x: number) => number; // Function type literal + func3: { (x: number): number }; // Object type literal } ``` the properties 'func1', 'func2', and 'func3' are all of the same type, namely an object type with a single call signature taking a number and returning a number. Likewise, in the object type ```TypeScript -{ - func4(x: number): number; - func4(s: string): string; - func5: { - (x: number): number; - (s: string): string; - }; +{ + func4(x: number): number; + func4(s: string): string; + func5: { + (x: number): number; + (s: string): string; + }; } ``` @@ -2121,7 +2122,7 @@ the properties 'func4' and 'func5' are of the same type, namely an object type w A type alias declaration introduces a ***type alias*** in the containing declaration space. -  *TypeAliasDeclaration:* +  *TypeAliasDeclaration:*    `type` *BindingIdentifier* *TypeParametersopt* `=` *Type* `;` A type alias serves as an alias for the type specified in the type alias declaration. Unlike an interface declaration, which always introduces a named object type, a type alias declaration can introduce a name for any kind of type, including primitive, union, and intersection types. @@ -2146,31 +2147,31 @@ Given this definition, the complete set of types upon which a type depends is th Some examples of type alias declarations: ```TypeScript -type StringOrNumber = string | number; -type Text = string | { text: string }; -type NameLookup = Dictionary; -type ObjectStatics = typeof Object; -type Callback = (data: T) => void; -type Pair = [T, T]; -type Coordinates = Pair; +type StringOrNumber = string | number; +type Text = string | { text: string }; +type NameLookup = Dictionary; +type ObjectStatics = typeof Object; +type Callback = (data: T) => void; +type Pair = [T, T]; +type Coordinates = Pair; type Tree = T | { left: Tree, right: Tree }; ``` Interface types have many similarities to type aliases for object type literals, but since interface types offer more capabilities they are generally preferred to type aliases. For example, the interface type ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } ``` could be written as the type alias ```TypeScript -type Point = { - x: number; - y: number; +type Point = { + x: number; + y: number; }; ``` @@ -2215,8 +2216,8 @@ In effect, a type's apparent members make it a subtype of the 'Object' or 'Funct Some examples: ```TypeScript -var o: Object = { x: 10, y: 20 }; // Ok -var f: Function = (x: number) => x * x; // Ok +var o: Object = { x: 10, y: 20 }; // Ok +var f: Function = (x: number) => x * x; // Ok var err: Object = { toString: 0 }; // Error ``` @@ -2254,7 +2255,7 @@ interface X { f(): string; } interface Y { f(): string; } -var a: C; +var a: C; var b: C; ``` @@ -2342,9 +2343,9 @@ The assignment compatibility rules imply that, when assigning values or passing ```TypeScript function foo(x: { id: number; name?: string; }) { } -foo({ id: 1234 }); // Ok -foo({ id: 1234, name: "hello" }); // Ok -foo({ id: 1234, name: false }); // Error, name of wrong type +foo({ id: 1234 }); // Ok +foo({ id: 1234, name: "hello" }); // Ok +foo({ id: 1234, name: false }); // Error, name of wrong type foo({ name: "hello" }); // Error, id required but missing ``` @@ -2372,16 +2373,16 @@ The type inferred for an object literal (as described in section [4.5](#4.5)) is Consider the following example: ```TypeScript -interface CompilerOptions { - strict?: boolean; - sourcePath?: string; - targetPath?: string; +interface CompilerOptions { + strict?: boolean; + sourcePath?: string; + targetPath?: string; } -var options: CompilerOptions = { - strict: true, - sourcepath: "./src", // Error, excess or misspelled property - targetpath: "./bin" // Error, excess or misspelled property +var options: CompilerOptions = { + strict: true, + sourcepath: "./src", // Error, excess or misspelled property + targetpath: "./bin" // Error, excess or misspelled property }; ``` @@ -2390,17 +2391,17 @@ The 'CompilerOptions' type contains only optional properties, so without the exc In cases where excess properties are expected, an index signature can be added to the target type as an indicator of intent: ```TypeScript -interface InputElement { - name: string; - visible?: boolean; - [x: string]: any; // Allow additional properties of any type +interface InputElement { + name: string; + visible?: boolean; + [x: string]: any; // Allow additional properties of any type } -var address: InputElement = { - name: "Address", - visible: true, - help: "Enter address here", // Allowed because of index signature - shortcut: "Alt-A" // Allowed because of index signature +var address: InputElement = { + name: "Address", + visible: true, + help: "Enter address here", // Allowed because of index signature + shortcut: "Alt-A" // Allowed because of index signature }; ``` @@ -2459,10 +2460,10 @@ When this same technique is used to compare generic type references, two type re In certain circumstances, generic types that directly or indirectly reference themselves in a recursive fashion can lead to infinite series of distinct instantiations. For example, in the type ```TypeScript -interface List { - data: T; - next: List; - owner: List>; +interface List { + data: T; + next: List; + owner: List>; } ``` @@ -2481,9 +2482,9 @@ infers the type of 'name' to be the String primitive type since that is the type The following example shows the results of widening types to produce inferred variable types. ```TypeScript -var a = null; // var a: any -var b = undefined; // var b: any -var c = { x: 0, y: null }; // var c: { x: number, y: any } +var a = null; // var a: any +var b = undefined; // var b: any +var c = { x: 0, y: null }; // var c: { x: number, y: any } var d = [ null, undefined ]; // var d: any[] ``` @@ -2547,18 +2548,18 @@ Literals are typed as follows: Object literals are extended to support type annotations in methods and get and set accessors. -  *PropertyDefinition:* *( Modified )* -   *IdentifierReference* -   *CoverInitializedName* -   *PropertyName* `:` *AssignmentExpression* -   *PropertyName* *CallSignature* `{` *FunctionBody* `}` -   *GetAccessor* +  *PropertyDefinition:* *( Modified )* +   *IdentifierReference* +   *CoverInitializedName* +   *PropertyName* `:` *AssignmentExpression* +   *PropertyName* *CallSignature* `{` *FunctionBody* `}` +   *GetAccessor*    *SetAccessor* -  *GetAccessor:* +  *GetAccessor:*    `get` *PropertyName* `(` `)` *TypeAnnotationopt* `{` *FunctionBody* `}` -  *SetAccessor:* +  *SetAccessor:*    `set` *PropertyName* `(` *BindingIdentifierOrPattern* *TypeAnnotationopt* `)` `{` *FunctionBody* `}` The type of an object literal is an object type with the set of properties specified by the property assignments in the object literal. A get and set accessor may specify the same property name, but otherwise it is an error to specify multiple property assignments for the same property. @@ -2644,22 +2645,22 @@ A spread element must specify an expression of an array-like type (section [3.3. The rules above mean that an array literal is always of an array type, unless it is contextually typed by a tuple-like type. For example ```TypeScript -var a = [1, 2]; // number[] -var b = ["hello", true]; // (string | boolean)[] +var a = [1, 2]; // number[] +var b = ["hello", true]; // (string | boolean)[] var c: [number, string] = [3, "three"]; // [number, string] ``` When the output target is ECMAScript 3 or 5, array literals containing spread elements are rewritten to invocations of the `concat` method. For example, the assignments ```TypeScript -var a = [2, 3, 4]; +var a = [2, 3, 4]; var b = [0, 1, ...a, 5, 6]; ``` are rewritten to ```TypeScript -var a = [2, 3, 4]; +var a = [2, 3, 4]; var b = [0, 1].concat(a, [5, 6]); ``` @@ -2710,7 +2711,7 @@ The JavaScript code generated for a super property access is specified in sectio Function expressions are extended from JavaScript to optionally include parameter and return type annotations. -  *FunctionExpression:* *( Modified )* +  *FunctionExpression:* *( Modified )*    `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` The descriptions of function declarations provided in chapter [6](#6) apply to function expressions as well, except that function expressions do not support overloading. @@ -2730,8 +2731,8 @@ A contextual signature *S* is extracted from a function type *T* as follows: In the example ```TypeScript -var f: (s: string) => string = function (s) { - return s.toLowerCase(); +var f: (s: string) => string = function (s) { + return s.toLowerCase(); }; ``` @@ -2741,7 +2742,7 @@ the function expression is contextually typed by the type of 'f', and since the Arrow functions are extended from JavaScript to optionally include parameter and return type annotations. -  *ArrowFormalParameters:* *( Modified )* +  *ArrowFormalParameters:* *( Modified )*    *CallSignature* The descriptions of function declarations provided in chapter [6](#6) apply to arrow functions as well, except that arrow functions do not support overloading. @@ -2765,23 +2766,23 @@ is exactly equivalent to Furthermore, arrow function expressions of the forms ```TypeScript -id => { ... } +id => { ... } id => expr ``` are exactly equivalent to ```TypeScript -( id ) => { ... } +( id ) => { ... } ( id ) => expr ``` Thus, the following examples are all equivalent: ```TypeScript -(x) => { return Math.sin(x); } -(x) => Math.sin(x) -x => { return Math.sin(x); } +(x) => { return Math.sin(x); } +(x) => Math.sin(x) +x => { return Math.sin(x); } x => Math.sin(x) ``` @@ -2790,29 +2791,29 @@ A function expression introduces a new dynamically bound `this`, whereas an arro In the example ```TypeScript -class Messenger { - message = "Hello World"; - start() { - setTimeout(() => alert(this.message), 3000); - } +class Messenger { + message = "Hello World"; + start() { + setTimeout(() => alert(this.message), 3000); + } }; -var messenger = new Messenger(); +var messenger = new Messenger(); messenger.start(); ``` the use of an arrow function expression causes the callback to have the same `this` as the surrounding 'start' method. Writing the callback as a standard function expression it becomes necessary to manually arrange access to the surrounding `this`, for example by copying it into a local variable: ```TypeScript -class Messenger { - message = "Hello World"; - start() { - var _this = this; - setTimeout(function() { alert(_this.message); }, 3000); - } +class Messenger { + message = "Hello World"; + start() { + var _this = this; + setTimeout(function() { alert(_this.message); }, 3000); + } }; -var messenger = new Messenger(); +var messenger = new Messenger(); messenger.start(); ``` @@ -2869,20 +2870,20 @@ where *object* and *index* are expressions, is used to access the property with The rules above mean that properties are strongly typed when accessed using bracket notation with the literal representation of their name. For example: ```TypeScript -var type = { - name: "boolean", - primitive: true +var type = { + name: "boolean", + primitive: true }; -var s = type["name"]; // string +var s = type["name"]; // string var b = type["primitive"]; // boolean ``` Tuple types assign numeric names to each of their elements and elements are therefore strongly typed when accessed using bracket notation with a numeric literal: ```TypeScript -var data: [string, number] = ["five", 5]; -var s = data[0]; // string +var data: [string, number] = ["five", 5]; +var s = data[0]; // string var n = data[1]; // number ``` @@ -2891,8 +2892,8 @@ var n = data[1]; // number A `new` operation has one of the following forms: ```TypeScript -new C -new C ( ... ) +new C +new C ( ... ) new C < ... > ( ... ) ``` @@ -2906,13 +2907,13 @@ where *C* is an expression. The first form is equivalent to supplying an empty a Function calls are extended from JavaScript to support optional type arguments. -  *Arguments:* *( Modified )* +  *Arguments:* *( Modified )*    *TypeArgumentsopt* `(` *ArgumentListopt* `)` A function call takes one of the forms ```TypeScript -func ( ... ) +func ( ... ) func < ... > ( ... ) ``` @@ -2979,11 +2980,11 @@ The process of inferentially typing an expression *e* by a type *T* is the same An example: ```TypeScript -function choose(x: T, y: T): T { - return Math.random() < 0.5 ? x : y; +function choose(x: T, y: T): T { + return Math.random() < 0.5 ? x : y; } -var x = choose(10, 20); // Ok, x of type number +var x = choose(10, 20); // Ok, x of type number var y = choose("Five", 5); // Error ``` @@ -2998,13 +2999,13 @@ In the second call to 'choose', an inference is made from type 'string' to 'T' f In the example ```TypeScript -function map(a: T[], f: (x: T) => U): U[] { - var result: U[] = []; - for (var i = 0; i < a.length; i++) result.push(f(a[i])); - return result; +function map(a: T[], f: (x: T) => U): U[] { + var result: U[] = []; + for (var i = 0; i < a.length; i++) result.push(f(a[i])); + return result; } -var names = ["Peter", "Paul", "Mary"]; +var names = ["Peter", "Paul", "Mary"]; var lengths = map(names, s => s.length); ``` @@ -3019,22 +3020,22 @@ and the resulting type of 'lengths' is therefore 'number[]'. In the example ```TypeScript -function zip(x: S[], y: T[], combine: (x: S) => (y: T) => U): U[] { - var len = Math.max(x.length, y.length); - var result: U[] = []; - for (var i = 0; i < len; i++) result.push(combine(x[i])(y[i])); - return result; +function zip(x: S[], y: T[], combine: (x: S) => (y: T) => U): U[] { + var len = Math.max(x.length, y.length); + var result: U[] = []; + for (var i = 0; i < len; i++) result.push(combine(x[i])(y[i])); + return result; } -var names = ["Peter", "Paul", "Mary"]; -var ages = [7, 9, 12]; +var names = ["Peter", "Paul", "Mary"]; +var ages = [7, 9, 12]; var pairs = zip(names, ages, s => n => ({ name: s, age: n })); ``` inferences for 'S', 'T' and 'U' in the call to 'zip' are made as follows: Using the first two parameters, inferences of 'string' for 'S' and 'number' for 'T' are made. For the third parameter, inferential typing of the outer arrow expression causes 'S' to become fixed such that the inferred type 'string' can be used for the parameter 's'. When a function expression is inferentially typed, its return expression(s) are also inferentially typed. Thus, the inner arrow function is inferentially typed, causing 'T' to become fixed such that the inferred type 'number' can be used for the parameter 'n'. The return type of the inner arrow function can then be determined, which in turn determines the return type of the function returned from the outer arrow function, and inferences are made from the type '(s: string) => (n: number) => { name: string; age: number }' to the type '(x: S) => (y: T) => R', inferring '{ name: string; age: number }' for 'R'. Thus the call to 'zip' is equivalent to ```TypeScript -var pairs = zip( +var pairs = zip( names, ages, s => n => ({ name: s, age: n })); ``` @@ -3055,7 +3056,7 @@ The grammar ambiguity is resolved as follows: In a context where one possible in This rule means that the call to 'f' above is interpreted as a call with one argument, which is a call to a generic function 'g' with two type arguments and one regular argument. However, the statements ```TypeScript -f(g < A, B > 7); +f(g < A, B > 7); f(g < A, B > +(7)); ``` @@ -3065,8 +3066,8 @@ are both interpreted as calls to 'f' with two arguments. TypeScript extends the JavaScript expression grammar with the ability to assert a type for an expression: -  *UnaryExpression:* *( Modified )* -   … +  *UnaryExpression:* *( Modified )* +   …    `<` *Type* `>` *UnaryExpression* A type assertion expression consists of a type enclosed in `<` and `>` followed by a unary expression. Type assertion expressions are purely a compile-time construct. Type assertions are *not* checked at run-time and have no impact on the emitted JavaScript (and therefore no run-time cost). The type and the enclosing `<` and `>` are simply removed from the generated code. @@ -3080,9 +3081,9 @@ class Shape { ... } class Circle extends Shape { ... } -function createShape(kind: string): Shape { - if (kind === "circle") return new Circle(); - ... +function createShape(kind: string): Shape { + if (kind === "circle") return new Circle(); + ... } var circle = createShape("circle"); @@ -3093,10 +3094,10 @@ the type annotations indicate that the 'createShape' function *might* return a ' As mentioned above, type assertions are not checked at run-time and it is up to the programmer to guard against errors, for example using the `instanceof` operator: ```TypeScript -var shape = createShape(shapeKind); -if (shape instanceof Circle) { - var circle = shape; - ... +var shape = createShape(shapeKind); +if (shape instanceof Circle) { + var circle = shape; + ... } ``` @@ -3155,8 +3156,8 @@ The 'void' operator takes an operand of any type and produces the value 'undefin The 'typeof' operator takes an operand of any type and produces a value of the String primitive type. In positions where a type is expected, 'typeof' can also be used in a type query (section [3.8.10](#3.8.10)) to produce the type of an expression. ```TypeScript -var x = 5; -var y = typeof x; // Use in an expression +var x = 5; +var y = typeof x; // Use in an expression var z: typeof x; // Use in a type query ``` @@ -3240,7 +3241,7 @@ The && operator permits the operands to be of any type and produces a result of The || operator permits the operands to be of any type. -If the || expression is contextually typed (section [4.23](#4.23)), the operands are contextually typed by the same type. Otherwise, the left operand is not contextually typed and the right operand is contextually typed by the type of the left operand. +If the || expression is contextually typed (section [4.23](#4.23)), the operands are contextually typed by the same type. Otherwise, the left operand is not contextually typed and the right operand is contextually typed by the type of the left operand. The type of the result is the union type of the two operand types. @@ -3301,7 +3302,7 @@ In a destructuring assignment expression, the type of the expression on the righ * *S* is the type Any, or * *S* has an apparent property with the property name specified in *P* of a type that is assignable to the target given in *P*, or * *P* specifies a numeric property name and *S* has a numeric index signature of a type that is assignable to the target given in *P*, or - * *S* has a string index signature of a type that is assignable to the target given in *P*. + * *S* has a string index signature of a type that is assignable to the target given in *P*. * *V* is an array assignment pattern, *S* is the type Any or an array-like type (section [3.3.2](#3.3.2)), and, for each assignment element *E* in *V*, * *S* is the type Any, or * *S* is a tuple-like type (section [3.3.3](#3.3.3)) with a property named *N* of a type that is assignable to the target given in *E*, where *N* is the numeric index of *E* in the array assignment pattern, or @@ -3314,17 +3315,17 @@ In an assignment property or element that includes a default value, the type of When the output target is ECMAScript 2015 or higher, destructuring variable assignments remain unchanged in the emitted JavaScript code. When the output target is ECMAScript 3 or 5, destructuring variable assignments are rewritten to series of simple assignments. For example, the destructuring assignment ```TypeScript -var x = 1; -var y = 2; +var x = 1; +var y = 2; [x, y] = [y, x]; ``` is rewritten to the simple variable assignments ```TypeScript -var x = 1; -var y = 2; -_a = [y, x], x = _a[0], y = _a[1]; +var x = 1; +var y = 2; +_a = [y, x], x = _a[0], y = _a[1]; var _a; ``` @@ -3348,13 +3349,13 @@ Type checking of an expression is improved in several contexts by factoring in t * In a contextually typed object literal, each property value expression is contextually typed by * the type of the property with a matching name in the contextual type, if any, or otherwise * for a numerically named property, the numeric index type of the contextual type, if any, or otherwise - * the string index type of the contextual type, if any. + * the string index type of the contextual type, if any. * In a contextually typed array literal expression containing no spread elements, an element expression at index *N* is contextually typed by * the type of the property with the numeric name *N* in the contextual type, if any, or otherwise * the numeric index type of the contextual type, if any. * In a contextually typed array literal expression containing one or more spread elements, an element expression at index *N* is contextually typed by the numeric index type of the contextual type, if any. * In a contextually typed parenthesized expression, the contained expression is contextually typed by the same type. -* In a type assertion, the expression is contextually typed by the indicated type. +* In a type assertion, the expression is contextually typed by the indicated type. * In a || operator expression, if the expression is contextually typed, the operands are contextually typed by the same type. Otherwise, the right expression is contextually typed by the type of the left expression. * In a contextually typed conditional operator expression, the operands are contextually typed by the same type. * In an assignment expression, the right hand expression is contextually typed by the type of the left hand expression. @@ -3362,22 +3363,22 @@ Type checking of an expression is improved in several contexts by factoring in t In the following example ```TypeScript -interface EventObject { - x: number; - y: number; +interface EventObject { + x: number; + y: number; } -interface EventHandlers { - mousedown?: (event: EventObject) => void; - mouseup?: (event: EventObject) => void; - mousemove?: (event: EventObject) => void; +interface EventHandlers { + mousedown?: (event: EventObject) => void; + mouseup?: (event: EventObject) => void; + mousemove?: (event: EventObject) => void; } function setEventHandlers(handlers: EventHandlers) { ... } -setEventHandlers({ - mousedown: e => { startTracking(e.x, e.y); }, - mouseup: e => { endTracking(); } +setEventHandlers({ + mousedown: e => { startTracking(e.x, e.y); }, + mouseup: e => { endTracking(); } }); ``` @@ -3388,13 +3389,13 @@ the object literal passed to 'setEventHandlers' is contextually typed to the 'Ev Type guards are particular expression patterns involving the 'typeof' and 'instanceof' operators that cause the types of variables or parameters to be ***narrowed*** to more specific types. For example, in the code below, knowledge of the static type of 'x' in combination with a 'typeof' check makes it safe to narrow the type of 'x' to string in the first branch of the 'if' statement and number in the second branch of the 'if' statement. ```TypeScript -function foo(x: number | string) { - if (typeof x === "string") { - return x.length; // x has type string here - } - else { - return x + 1; // x has type number here - } +function foo(x: number | string) { + if (typeof x === "string") { + return x.length; // x has type string here + } + else { + return x + 1; // x has type number here + } } ``` @@ -3441,8 +3442,8 @@ Note that type guards affect types of variables and parameters only and have no In the example ```TypeScript -function isLongString(obj: any) { - return typeof obj === "string" && obj.length > 100; +function isLongString(obj: any) { + return typeof obj === "string" && obj.length > 100; } ``` @@ -3451,9 +3452,9 @@ the `obj` parameter has type `string` in the right operand of the && operator. In the example ```TypeScript -function processValue(value: number | (() => number)) { - var x = typeof value !== "number" ? value() : value; - // Process number in x +function processValue(value: number | (() => number)) { + var x = typeof value !== "number" ? value() : value; + // Process number in x } ``` @@ -3462,13 +3463,13 @@ the value parameter has type `() => number` in the first conditional expression In the example ```TypeScript -function f(x: string | number | boolean) { - if (typeof x === "string" || typeof x === "number") { - var y = x; // Type of y is string | number - } - else { - var z = x; // Type of z is boolean - } +function f(x: string | number | boolean) { + if (typeof x === "string" || typeof x === "number") { + var y = x; // Type of y is string | number + } + else { + var z = x; // Type of z is boolean + } } ``` @@ -3477,12 +3478,12 @@ the type of x is `string | number | boolean` in the left operand of the || opera In the example ```TypeScript -class C { - data: string | string[]; - getData() { - var data = this.data; - return typeof data === "string" ? data : data.join(" "); - } +class C { + data: string | string[]; + getData() { + var data = this.data; + return typeof data === "string" ? data : data.join(" "); + } } ``` @@ -3491,12 +3492,12 @@ the type of the `data` variable is `string` in the first conditional expression In the example ```TypeScript -class NamedItem { - name: string; +class NamedItem { + name: string; } -function getName(obj: Object) { - return obj instanceof NamedItem ? obj.name : "unknown"; +function getName(obj: Object) { + return obj instanceof NamedItem ? obj.name : "unknown"; } ``` @@ -3512,10 +3513,10 @@ This chapter describes the static type checking TypeScript provides for JavaScri Blocks are extended to include local interface, type alias, and enum declarations (classes are already included by the ECMAScript 2015 grammar). -  *Declaration:* *( Modified )* -   … -   *InterfaceDeclaration* -   *TypeAliasDeclaration* +  *Declaration:* *( Modified )* +   … +   *InterfaceDeclaration* +   *TypeAliasDeclaration*    *EnumDeclaration* Local class, interface, type alias, and enum declarations are block scoped, similar to let and const declarations. @@ -3524,8 +3525,8 @@ Local class, interface, type alias, and enum declarations are block scoped, simi Variable statements are extended to include optional type annotations. -  *VariableDeclaration:* *( Modified )* -   *SimpleVariableDeclaration* +  *VariableDeclaration:* *( Modified )* +   *SimpleVariableDeclaration*    *DestructuringVariableDeclaration* A variable declaration is either a simple variable declaration or a destructuring variable declaration. @@ -3534,7 +3535,7 @@ A variable declaration is either a simple variable declaration or a destructurin A ***simple variable declaration*** introduces a single named variable and optionally assigns it an initial value. -  *SimpleVariableDeclaration:* +  *SimpleVariableDeclaration:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* The type *T* of a variable introduced by a simple variable declaration is determined as follows: @@ -3552,20 +3553,20 @@ When a variable declaration has a type annotation, it is an error for that type Below are some examples of simple variable declarations and their associated types. ```TypeScript -var a; // any -var b: number; // number -var c = 1; // number -var d = { x: 1, y: "hello" }; // { x: number; y: string; } +var a; // any +var b: number; // number +var c = 1; // number +var d = { x: 1, y: "hello" }; // { x: number; y: string; } var e: any = "test"; // any ``` The following is permitted because all declarations of the single variable 'x' associate the same type (Number) with 'x'. ```TypeScript -var x = 1; -var x: number; -if (x == 1) { - var x = 2; +var x = 1; +var x: number; +if (x == 1) { + var x = 2; } ``` @@ -3574,10 +3575,10 @@ In the following example, all five variables are of the same type, '{ x: number; ```TypeScript interface Point { x: number; y: number; } -var a = { x: 0, y: undefined }; -var b: Point = { x: 0, y: undefined }; -var c = { x: 0, y: undefined }; -var d: { x: number; y: number; } = { x: 0, y: undefined }; +var a = { x: 0, y: undefined }; +var b: Point = { x: 0, y: undefined }; +var c = { x: 0, y: undefined }; +var d: { x: number; y: number; } = { x: 0, y: undefined }; var e = <{ x: number; y: number; }> { x: 0, y: undefined }; ``` @@ -3585,7 +3586,7 @@ var e = <{ x: number; y: number; }> { x: 0, y: undefined }; A ***destructuring variable declaration*** introduces zero or more named variables and initializes them with values extracted from properties of an object or elements of an array. -  *DestructuringVariableDeclaration:* +  *DestructuringVariableDeclaration:*    *BindingPattern* *TypeAnnotationopt* *Initializer* Each binding property or element that specifies an identifier introduces a variable by that name. The type of the variable is the widened form (section [3.12](#3.12)) of the type associated with the binding property or element, as defined in the following. @@ -3640,10 +3641,10 @@ var { x, p: y, q: z = false } = getSomeObject(); is rewritten to the simple variable declarations ```TypeScript -var _a = getSomeObject(), - x = _a.x, - y = _a.p, - _b = _a.q, +var _a = getSomeObject(), + x = _a.x, + y = _a.p, + _b = _a.q, z = _b === void 0 ? false : _b; ``` @@ -3658,10 +3659,10 @@ var [x, y, z = 10] = getSomeArray(); is rewritten to the simple variable declarations ```TypeScript -var _a = getSomeArray(), - x = _a[0], - y = _a[1], - _b = _a[2], +var _a = getSomeArray(), + x = _a[0], + y = _a[1], + _b = _a[2], z = _b === void 0 ? 10 : _b; ``` @@ -3674,12 +3675,12 @@ var { x, p: [y, z = 10] = getSomeArray() } = getSomeObject(); is rewritten to ```TypeScript -var _a = getSomeObject(), - x = _a.x, - _b = _a.p, - _c = _b === void 0 ? getSomeArray() : _b, - y = _c[0], - _d = _c[1], +var _a = getSomeObject(), + x = _a.x, + _b = _a.p, + _c = _b === void 0 ? getSomeArray() : _b, + y = _c[0], + _d = _c[1], z = _d === void 0 ? 10 : _d; ``` @@ -3717,14 +3718,14 @@ the array literal initializer expression is contextually typed by the implied ty Let and const declarations are exended to include optional type annotations. -  *LexicalBinding:* *( Modified )* -   *SimpleLexicalBinding* +  *LexicalBinding:* *( Modified )* +   *SimpleLexicalBinding*    *DestructuringLexicalBinding* -  *SimpleLexicalBinding:* +  *SimpleLexicalBinding:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* -  *DestructuringLexicalBinding:* +  *DestructuringLexicalBinding:*    *BindingPattern* *TypeAnnotationopt* *Initializeropt* *TODO: Document scoping and types of [let and const declarations](https://github.com/Microsoft/TypeScript/pull/904)*. @@ -3780,8 +3781,8 @@ In a function implementation without a return type annotation, the return type i In the example ```TypeScript -function f(): (x: string) => number { - return s => s.length; +function f(): (x: string) => number { + return s => s.length; } ``` @@ -3813,8 +3814,8 @@ TypeScript extends JavaScript functions to include type parameters, parameter an Function declarations are extended to permit the function body to be omitted in overload declarations. -  *FunctionDeclaration:* *( Modified )* -   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` +  *FunctionDeclaration:* *( Modified )* +   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}`    `function` *BindingIdentifieropt* *CallSignature* `;` A *FunctionDeclaration* introduces a named value of a function type in the containing declaration space. The *BindingIdentifier* is optional only when the function declaration occurs in an export default declaration (section [11.3.4.2](#11.3.4.2)). @@ -3836,26 +3837,26 @@ The parameter list of a function overload cannot specify default values for para The following is an example of a function with overloads. ```TypeScript -function attr(name: string): string; -function attr(name: string, value: string): Accessor; -function attr(map: any): Accessor; -function attr(nameOrMap: any, value?: string): any { - if (nameOrMap && typeof nameOrMap === "string") { - // handle string case - } - else { - // handle map case - } +function attr(name: string): string; +function attr(name: string, value: string): Accessor; +function attr(map: any): Accessor; +function attr(nameOrMap: any, value?: string): any { + if (nameOrMap && typeof nameOrMap === "string") { + // handle string case + } + else { + // handle map case + } } ``` Note that each overload and the final implementation specify the same identifier. The type of the local variable 'attr' introduced by this declaration is ```TypeScript -var attr: { - (name: string): string; - (name: string, value: string): Accessor; - (map: any): Accessor; +var attr: { + (name: string): string; + (name: string, value: string): Accessor; + (map: any): Accessor; }; ``` @@ -3873,13 +3874,13 @@ A function implementation without a return type annotation is said to be an ***i In the example ```TypeScript -function f(x: number) { - if (x <= 0) return x; - return g(x); +function f(x: number) { + if (x <= 0) return x; + return g(x); } -function g(x: number) { - return f(x - 1); +function g(x: number) { + return f(x - 1); } ``` @@ -3896,27 +3897,27 @@ Initializer expressions are evaluated in the scope of the function body but are When the output target is ECMAScript 3 or 5, for each parameter with an initializer, a statement that substitutes the default value for an omitted argument is included in the generated JavaScript, as described in section [6.6](#6.6). The example ```TypeScript -function strange(x: number, y = x * 2, z = x + y) { - return z; +function strange(x: number, y = x * 2, z = x + y) { + return z; } ``` generates JavaScript that is equivalent to ```TypeScript -function strange(x, y, z) { - if (y === void 0) { y = x * 2; } - if (z === void 0) { z = x + y; } - return z; +function strange(x, y, z) { + if (y === void 0) { y = x * 2; } + if (z === void 0) { z = x + y; } + return z; } ``` In the example ```TypeScript -var x = 1; -function f(a = x) { - var x = "hello"; +var x = 1; +function f(a = x) { + var x = "hello"; } ``` @@ -3940,8 +3941,8 @@ When the output target is ECMAScript 2015 or higher, except for removing the opt The example ```TypeScript -function drawText({ text = "", location: [x, y] = [0, 0], bold = false }) { - // Draw text +function drawText({ text = "", location: [x, y] = [0, 0], bold = false }) { + // Draw text } ``` @@ -3954,30 +3955,30 @@ declares a function `drawText` that takes a single parameter of the type When the output target is ECMAScript 3 or 5, the function is rewritten to ```TypeScript -function drawText(_a) { - var _b = _a.text, - text = _b === void 0 ? "" : _b, - _c = _a.location, - _d = _c === void 0 ? [0, 0] : _c, - x = _d[0], - y = _d[1], - _e = _a.bold, - bold = _e === void 0 ? false : _e; - // Draw text +function drawText(_a) { + var _b = _a.text, + text = _b === void 0 ? "" : _b, + _c = _a.location, + _d = _c === void 0 ? [0, 0] : _c, + x = _d[0], + y = _d[1], + _e = _a.bold, + bold = _e === void 0 ? false : _e; + // Draw text } ``` Destructuring parameter declarations do not permit type annotations on the individual binding patterns, as such annotations would conflict with the already established meaning of colons in object literals. Type annotations must instead be written on the top-level parameter declaration. For example ```TypeScript -interface DrawTextInfo { - text?: string; - location?: [number, number]; - bold?: boolean; +interface DrawTextInfo { + text?: string; + location?: [number, number]; + bold?: boolean; } -function drawText({ text, location: [x, y], bold }: DrawTextInfo) { - // Draw text +function drawText({ text, location: [x, y], bold }: DrawTextInfo) { + // Draw text } ``` @@ -3990,14 +3991,14 @@ Type parameters declared in the signature of a function implementation are in sc The following is an example of a generic function: ```TypeScript -interface Comparable { - localeCompare(other: any): number; +interface Comparable { + localeCompare(other: any): number; } -function compare(x: T, y: T): number { - if (x == null) return y == null ? 0 : -1; - if (y == null) return 1; - return x.localeCompare(y); +function compare(x: T, y: T): number { + if (x == null) return y == null ? 0 : -1; + if (y == null) return 1; + return x.localeCompare(y); } ``` @@ -4006,11 +4007,11 @@ Note that the 'x' and 'y' parameters are known to be subtypes of the constraint The type arguments of a call to a generic function may be explicitly specified in a call operation or may, when possible, be inferred (section [4.15.2](#4.15.2)) from the types of the regular arguments in the call. In the example ```TypeScript -class Person { - name: string; - localeCompare(other: Person) { - return compare(this.name, other.name); - } +class Person { + name: string; + localeCompare(other: Person) { + return compare(this.name, other.name); + } } ``` @@ -4021,9 +4022,9 @@ the type argument to 'compare' is automatically inferred to be the String type b A function declaration generates JavaScript code that is equivalent to: ```TypeScript -function () { - - +function () { + + } ``` @@ -4069,17 +4070,17 @@ Class declarations may reference interfaces in their implements clause to valida An interface declaration declares an ***interface type***. -  *InterfaceDeclaration:* +  *InterfaceDeclaration:*    `interface` *BindingIdentifier* *TypeParametersopt* *InterfaceExtendsClauseopt* *ObjectType* -  *InterfaceExtendsClause:* +  *InterfaceExtendsClause:*    `extends` *ClassOrInterfaceTypeList* -  *ClassOrInterfaceTypeList:* -   *ClassOrInterfaceType* +  *ClassOrInterfaceTypeList:* +   *ClassOrInterfaceType*    *ClassOrInterfaceTypeList* `,` *ClassOrInterfaceType* -  *ClassOrInterfaceType:* +  *ClassOrInterfaceType:*    *TypeReference* An *InterfaceDeclaration* introduces a named type (section [3.7](#3.7)) in the containing declaration space. The *BindingIdentifier* of an interface declaration may not be one of the predefined type names (section [3.8.1](#3.8.1)). @@ -4107,22 +4108,22 @@ An interface is permitted to inherit identical members from multiple base types Below is an example of two interfaces that contain properties with the same name but different types: ```TypeScript -interface Mover { - move(): void; - getStatus(): { speed: number; }; +interface Mover { + move(): void; + getStatus(): { speed: number; }; } -interface Shaker { - shake(): void; - getStatus(): { frequency: number; }; +interface Shaker { + shake(): void; + getStatus(): { frequency: number; }; } ``` An interface that extends 'Mover' and 'Shaker' must declare a new 'getStatus' property as it would otherwise inherit two 'getStatus' properties with different types. The new 'getStatus' property must be declared such that the resulting 'MoverShaker' is a subtype of both 'Mover' and 'Shaker': ```TypeScript -interface MoverShaker extends Mover, Shaker { - getStatus(): { speed: number; frequency: number; }; +interface MoverShaker extends Mover, Shaker { + getStatus(): { speed: number; frequency: number; }; } ``` @@ -4145,30 +4146,30 @@ In an interface with multiple declarations, the `extends` clauses are merged int For example, a sequence of declarations in this order: ```TypeScript -interface Document { - createElement(tagName: any): Element; +interface Document { + createElement(tagName: any): Element; } -interface Document { - createElement(tagName: string): HTMLElement; +interface Document { + createElement(tagName: string): HTMLElement; } -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; +interface Document { + createElement(tagName: "div"): HTMLDivElement; + createElement(tagName: "span"): HTMLSpanElement; + createElement(tagName: "canvas"): HTMLCanvasElement; } ``` is equivalent to the following single declaration: ```TypeScript -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; - createElement(tagName: string): HTMLElement; - createElement(tagName: any): Element; +interface Document { + createElement(tagName: "div"): HTMLDivElement; + createElement(tagName: "span"): HTMLSpanElement; + createElement(tagName: "canvas"): HTMLCanvasElement; + createElement(tagName: string): HTMLElement; + createElement(tagName: any): Element; } ``` @@ -4181,27 +4182,27 @@ Note that the members of the last interface declaration appear first in the merg When an interface type extends a class type it inherits the members of the class but not their implementations. It is as if the interface had declared all of the members of the class without providing an implementation. Interfaces inherit even the private and protected members of a base class. When a class containing private or protected members is the base type of an interface type, that interface type can only be implemented by that class or a descendant class. For example: ```TypeScript -class Control { - private state: any; +class Control { + private state: any; } -interface SelectableControl extends Control { - select(): void; +interface SelectableControl extends Control { + select(): void; } -class Button extends Control { - select() { } +class Button extends Control { + select() { } } -class TextBox extends Control { - select() { } +class TextBox extends Control { + select() { } } -class Image extends Control { +class Image extends Control { } -class Location { - select() { } +class Location { + select() { } } ``` @@ -4214,18 +4215,18 @@ Within the 'Control' class it is possible to access the 'state' private member t TypeScript does not provide a direct mechanism for dynamically testing whether an object implements a particular interface. Instead, TypeScript code can use the JavaScript technique of checking whether an appropriate set of members are present on the object. For example, given the declarations in section [7.1](#7.1), the following is a dynamic check for the 'MoverShaker' interface: ```TypeScript -var obj: any = getSomeObject(); -if (obj && obj.move && obj.shake && obj.getStatus) { - var moverShaker = obj; - ... +var obj: any = getSomeObject(); +if (obj && obj.move && obj.shake && obj.getStatus) { + var moverShaker = obj; + ... } ``` If such a check is used often it can be abstracted into a function: ```TypeScript -function asMoverShaker(obj: any): MoverShaker { - return obj && obj.move && obj.shake && obj.getStatus ? obj : null; +function asMoverShaker(obj: any): MoverShaker { + return obj && obj.move && obj.shake && obj.getStatus ? obj : null; } ``` @@ -4241,7 +4242,7 @@ TypeScript extends JavaScript classes to include type parameters, implements cla A class declaration declares a ***class type*** and a ***constructor function***. -  *ClassDeclaration:* *( Modified )* +  *ClassDeclaration:* *( Modified )*    `class` *BindingIdentifieropt* *TypeParametersopt* *ClassHeritage* `{` *ClassBody* `}` A *ClassDeclaration* introduces a named type (the class type) and a named value (the constructor function) in the containing declaration space. The class type is formed from the instance members declared in the class body and the instance members inherited from the base class. The constructor function is given an anonymous type formed from the constructor declaration, the static member declarations in the class body, and the static members inherited from the base class. The constructor function initializes and returns an instance of the class type. @@ -4253,29 +4254,29 @@ A class may optionally have type parameters (section [3.6.1](#3.6.1)) that serve The following example introduces both a named type called 'Point' (the class type) and a named value called 'Point' (the constructor function) in the containing declaration space. ```TypeScript -class Point { - constructor(public x: number, public y: number) { } - public length() { return Math.sqrt(this.x * this.x + this.y * this.y); } - static origin = new Point(0, 0); +class Point { + constructor(public x: number, public y: number) { } + public length() { return Math.sqrt(this.x * this.x + this.y * this.y); } + static origin = new Point(0, 0); } ``` The named type 'Point' is exactly equivalent to ```TypeScript -interface Point { - x: number; - y: number; - length(): number; +interface Point { + x: number; + y: number; + length(): number; } ``` The named value 'Point' is a constructor function whose type corresponds to the declaration ```TypeScript -var Point: { - new(x: number, y: number): Point; - origin: Point; +var Point: { + new(x: number, y: number): Point; + origin: Point; }; ``` @@ -4293,16 +4294,16 @@ the identifier 'Point' in the type annotation refers to the class type, whereas The heritage specification of a class consists of optional `extends` and `implements` clauses. The `extends` clause specifies the base class of the class and the `implements` clause specifies a set of interfaces for which to validate the class provides an implementation. -  *ClassHeritage:* *( Modified )* +  *ClassHeritage:* *( Modified )*    *ClassExtendsClauseopt* *ImplementsClauseopt* -  *ClassExtendsClause:* +  *ClassExtendsClause:*    `extends`  *ClassType* -  *ClassType:* +  *ClassType:*    *TypeReference* -  *ImplementsClause:* +  *ImplementsClause:*    `implements` *ClassOrInterfaceTypeList* A class that includes an `extends` clause is called a ***derived class***, and the class specified in the `extends` clause is called the ***base class*** of the derived class. When a class heritage specification omits the `extends` clause, the class does not have a base class. However, as is the case with every object type, type references (section [3.3.1](#3.3.1)) to the class will appear to have the members of the global interface type named 'Object' unless those members are hidden by members with the same name in the class. @@ -4319,9 +4320,9 @@ The following example illustrates a situation in which the first rule above woul ```TypeScript class A { a: number; } -namespace Foo { - var A = 1; - class B extends A { b: string; } +namespace Foo { + var A = 1; + class B extends A { b: string; } } ``` @@ -4335,9 +4336,9 @@ Note that because TypeScript has a structural type system, a class doesn't need The class body consists of zero or more constructor or member declarations. Statements are not allowed in the body of a class—they must be placed in the constructor or in members. -  *ClassElement:* *( Modified )* -   *ConstructorDeclaration* -   *PropertyMemberDeclaration* +  *ClassElement:* *( Modified )* +   *ConstructorDeclaration* +   *PropertyMemberDeclaration*    *IndexMemberDeclaration* The body of class may optionally contain a single constructor declaration. Constructor declarations are described in section [8.3](#8.3). @@ -4373,24 +4374,24 @@ Private and protected accessibility is enforced only at compile-time and serves The following example demonstrates private and protected accessibility: ```TypeScript -class A { - private x: number; - protected y: number; - static f(a: A, b: B) { - a.x = 1; // Ok - b.x = 1; // Ok - a.y = 1; // Ok - b.y = 1; // Ok - } +class A { + private x: number; + protected y: number; + static f(a: A, b: B) { + a.x = 1; // Ok + b.x = 1; // Ok + a.y = 1; // Ok + b.y = 1; // Ok + } } -class B extends A { - static f(a: A, b: B) { - a.x = 1; // Error, x only accessible within A - b.x = 1; // Error, x only accessible within A - a.y = 1; // Error, y must be accessed through instance of B - b.y = 1; // Ok - } +class B extends A { + static f(a: A, b: B) { + a.x = 1; // Error, x only accessible within A + b.x = 1; // Error, x only accessible within A + a.y = 1; // Error, y must be accessed through instance of B + b.y = 1; // Ok + } } ``` @@ -4426,37 +4427,37 @@ All instance property members (including those that are private or protected) of In the example ```TypeScript -class A { - public x: number; - public f() { } - public g(a: any) { return undefined; } - static s: string; +class A { + public x: number; + public f() { } + public g(a: any) { return undefined; } + static s: string; } -class B extends A { - public y: number; - public g(b: boolean) { return false; } +class B extends A { + public y: number; + public g(b: boolean) { return false; } } ``` the class type of 'A' is equivalent to ```TypeScript -interface A { - x: number; - f: () => void; - g: (a: any) => any; +interface A { + x: number; + f: () => void; + g: (a: any) => any; } ``` and the class type of 'B' is equivalent to ```TypeScript -interface B { - x: number; - y: number; - f: () => void; - g: (b: boolean) => boolean; +interface B { + x: number; + y: number; + f: () => void; + g: (b: boolean) => boolean; } ``` @@ -4481,8 +4482,8 @@ Every class automatically contains a static property member named 'prototype', t The example ```TypeScript -class Pair { - constructor(public item1: T1, public item2: T2) { } +class Pair { + constructor(public item1: T1, public item2: T2) { } } class TwoArrays extends Pair { } @@ -4491,26 +4492,26 @@ class TwoArrays extends Pair { } introduces two named types corresponding to ```TypeScript -interface Pair { - item1: T1; - item2: T2; +interface Pair { + item1: T1; + item2: T2; } -interface TwoArrays { - item1: T[]; - item2: T[]; +interface TwoArrays { + item1: T[]; + item2: T[]; } ``` and two constructor functions corresponding to ```TypeScript -var Pair: { - new (item1: T1, item2: T2): Pair; +var Pair: { + new (item1: T1, item2: T2): Pair; } -var TwoArrays: { - new (item1: T[], item2: T[]): TwoArrays; +var TwoArrays: { + new (item1: T[], item2: T[]): TwoArrays; } ``` @@ -4520,8 +4521,8 @@ Note that each construct signature in the constructor function types has the sam A constructor declaration declares the constructor function of a class. -  *ConstructorDeclaration:* -   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}` +  *ConstructorDeclaration:* +   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}`    *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `;` Constructor declarations that specify a body are called ***constructor implementations*** and constructor declarations without a body are called ***constructor overloads***. It is possible to specify multiple constructor overloads in a class, but a class can have at most one constructor implementation. All constructor declarations in a class must specify the same set of modifiers. Only public constructors are supported and private or protected constructors result in an error. @@ -4543,24 +4544,24 @@ Similar to functions, only the constructor implementation (and not constructor o A parameter of a *ConstructorImplementation* may be prefixed with a `public`, `private`, or `protected` modifier. This is called a ***parameter property declaration*** and is shorthand for declaring a property with the same name as the parameter and initializing it with the value of the parameter. For example, the declaration ```TypeScript -class Point { - constructor(public x: number, public y: number) { - // Constructor body - } +class Point { + constructor(public x: number, public y: number) { + // Constructor body + } } ``` is equivalent to writing ```TypeScript -class Point { - public x: number; - public y: number; - constructor(x: number, y: number) { - this.x = x; - this.y = y; - // Constructor body - } +class Point { + public x: number; + public y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + // Constructor body + } } ``` @@ -4571,10 +4572,10 @@ A parameter property declaration may declare an optional parameter (by including Super calls (section [4.9.1](#4.9.1)) are used to call the constructor of the base class. A super call consists of the keyword `super` followed by an argument list enclosed in parentheses. For example: ```TypeScript -class ColoredPoint extends Point { - constructor(x: number, y: number, public color: string) { - super(x, y); - } +class ColoredPoint extends Point { + constructor(x: number, y: number, public color: string) { + super(x, y); + } } ``` @@ -4607,9 +4608,9 @@ and then executes the instance member variable initializers, if any. Property member declarations can be member variable declarations, member function declarations, or member accessor declarations. -  *PropertyMemberDeclaration:* -   *MemberVariableDeclaration* -   *MemberFunctionDeclaration* +  *PropertyMemberDeclaration:* +   *MemberVariableDeclaration* +   *MemberFunctionDeclaration*    *MemberAccessorDeclaration* Member declarations without a `static` modifier are called instance member declarations. Instance property member declarations declare properties in the class type (section [8.2.4](#8.2.4)), and must specify names that are unique among all instance property member and parameter property declarations in the containing class, with the exception that instance get and set accessor declarations may pairwise specify the same name. @@ -4625,35 +4626,35 @@ Every class automatically contains a static property member named 'prototype', t Below is an example of a class containing both instance and static property member declarations: ```TypeScript -class Point { - constructor(public x: number, public y: number) { } - public distance(p: Point) { - var dx = this.x - p.x; - var dy = this.y - p.y; - return Math.sqrt(dx * dx + dy * dy); - } - static origin = new Point(0, 0); - static distance(p1: Point, p2: Point) { return p1.distance(p2); } +class Point { + constructor(public x: number, public y: number) { } + public distance(p: Point) { + var dx = this.x - p.x; + var dy = this.y - p.y; + return Math.sqrt(dx * dx + dy * dy); + } + static origin = new Point(0, 0); + static distance(p1: Point, p2: Point) { return p1.distance(p2); } } ``` The class type 'Point' has the members: ```TypeScript -interface Point { - x: number; - y: number; - distance(p: Point); +interface Point { + x: number; + y: number; + distance(p: Point); } ``` and the constructor function 'Point' has a type corresponding to the declaration: ```TypeScript -var Point: { - new(x: number, y: number): Point; - origin: Point; - distance(p1: Point, p2: Point): number; +var Point: { + new(x: number, y: number): Point; + origin: Point; + distance(p1: Point, p2: Point): number; } ``` @@ -4661,7 +4662,7 @@ var Point: { A member variable declaration declares an instance member variable or a static member variable. -  *MemberVariableDeclaration:* +  *MemberVariableDeclaration:*    *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* *Initializeropt* `;` The type associated with a member variable declaration is determined in the same manner as an ordinary variable declaration (see section [5.2](#5.2)). @@ -4675,29 +4676,29 @@ Initializer expressions for instance member variables are evaluated in the scope Since instance member variable initializers are equivalent to assignments to properties of `this` in the constructor, the example ```TypeScript -class Employee { - public name: string; - public address: string; - public retired = false; - public manager: Employee = null; - public reports: Employee[] = []; +class Employee { + public name: string; + public address: string; + public retired = false; + public manager: Employee = null; + public reports: Employee[] = []; } ``` is equivalent to ```TypeScript -class Employee { - public name: string; - public address: string; - public retired: boolean; - public manager: Employee; - public reports: Employee[]; - constructor() { - this.retired = false; - this.manager = null; - this.reports = []; - } +class Employee { + public name: string; + public address: string; + public retired: boolean; + public manager: Employee; + public reports: Employee[]; + constructor() { + this.retired = false; + this.manager = null; + this.reports = []; + } } ``` @@ -4705,8 +4706,8 @@ class Employee { A member function declaration declares an instance member function or a static member function. -  *MemberFunctionDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}` +  *MemberFunctionDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` A member function declaration is processed in the same manner as an ordinary function declaration (section [6](#6)), except that in a member function `this` has a known type. @@ -4720,48 +4721,48 @@ A static member function declaration declares a property in the constructor func A member function can access overridden base class members using a super property access (section [4.9.2](#4.9.2)). For example ```TypeScript -class Point { - constructor(public x: number, public y: number) { } - public toString() { - return "x=" + this.x + " y=" + this.y; - } +class Point { + constructor(public x: number, public y: number) { } + public toString() { + return "x=" + this.x + " y=" + this.y; + } } -class ColoredPoint extends Point { - constructor(x: number, y: number, public color: string) { - super(x, y); - } - public toString() { - return super.toString() + " color=" + this.color; - } +class ColoredPoint extends Point { + constructor(x: number, y: number, public color: string) { + super(x, y); + } + public toString() { + return super.toString() + " color=" + this.color; + } } ``` In a static member function, `this` represents the constructor function object on which the static member function was invoked. Thus, a call to 'new this()' may actually invoke a derived class constructor: ```TypeScript -class A { - a = 1; - static create() { - return new this(); - } +class A { + a = 1; + static create() { + return new this(); + } } -class B extends A { - b = 2; +class B extends A { + b = 2; } -var x = A.create(); // new A() +var x = A.create(); // new A() var y = B.create(); // new B() ``` Note that TypeScript doesn't require or verify that derived constructor functions are subtypes of base constructor functions. In other words, changing the declaration of 'B' to ```TypeScript -class B extends A { - constructor(public b: number) { - super(); - } +class B extends A { + constructor(public b: number) { + super(); + } } ``` @@ -4771,8 +4772,8 @@ does not cause errors in the example, even though the call to the constructor fr A member accessor declaration declares an instance member accessor or a static member accessor. -  *MemberAccessorDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *GetAccessor* +  *MemberAccessorDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *GetAccessor*    *AccessibilityModifieropt* `static`*opt* *SetAccessor* Get and set accessors are processed in the same manner as in an object literal (section [4.5](#4.5)), except that a contextual type is never available in a member accessor declaration. @@ -4797,7 +4798,7 @@ If the *PropertyName* of a property member declaration is a computed property na An index member declaration introduces an index signature (section [3.9.4](#3.9.4)) in the class type. -  *IndexMemberDeclaration:* +  *IndexMemberDeclaration:*    *IndexSignature* `;` Index member declarations have no body and cannot specify an accessibility modifier. @@ -4821,16 +4822,16 @@ When the output target is ECMAScript 2015 or higher, type parameters, implements A class with no `extends` clause generates JavaScript equivalent to the following: ```TypeScript -var = (function () { - function () { - - - - - } - - - return ; +var = (function () { + function () { + + + + + } + + + return ; })(); ``` @@ -4863,18 +4864,18 @@ where *MemberName* is the name of the member variable and *InitializerExpression An instance member function declaration generates a statement of the form ```TypeScript -.prototype. = function () { - - +.prototype. = function () { + + } ``` and static member function declaration generates a statement of the form ```TypeScript -. = function () { - - +. = function () { + + } ``` @@ -4883,30 +4884,30 @@ where *MemberName* is the name of the member function, and *FunctionParameters*, A get or set instance member accessor declaration, or a pair of get and set instance member accessor declarations with the same name, generates a statement of the form ```TypeScript -Object.defineProperty(.prototype, "", { - get: function () { - - }, - set: function () { - - }, - enumerable: true, - configurable: true +Object.defineProperty(.prototype, "", { + get: function () { + + }, + set: function () { + + }, + enumerable: true, + configurable: true }; ``` and a get or set static member accessor declaration, or a pair of get and set static member accessor declarations with the same name, generates a statement of the form ```TypeScript -Object.defineProperty(, "", { - get: function () { - - }, - set: function () { - - }, - enumerable: true, - configurable: true +Object.defineProperty(, "", { + get: function () { + + }, + set: function () { + + }, + enumerable: true, + configurable: true }; ``` @@ -4925,29 +4926,29 @@ where *MemberName* is the name of the static variable, and *InitializerExpressio A class with an `extends` clause generates JavaScript equivalent to the following: ```TypeScript -var = (function (_super) { - __extends(, _super); - function () { - - - - - - } - - - return ; +var = (function (_super) { + __extends(, _super); + function () { + + + + + + } + + + return ; })(); ``` In addition, the '__extends' function below is emitted at the beginning of the JavaScript source file. It copies all properties from the base constructor function object to the derived constructor function object (in order to inherit static members), and appropriately establishes the 'prototype' property of the derived constructor function object. ```TypeScript -var __extends = this.__extends || function(d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function f() { this.constructor = d; } - f.prototype = b.prototype; - d.prototype = new f(); +var __extends = this.__extends || function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function f() { this.constructor = d; } + f.prototype = b.prototype; + d.prototype = new f(); } ``` @@ -5005,7 +5006,7 @@ An enum type is a distinct subtype of the Number primitive type with an associat An enum declaration declares an ***enum type*** and an ***enum object***. -  *EnumDeclaration:* +  *EnumDeclaration:*    `const`*opt* `enum` *BindingIdentifier* `{` *EnumBodyopt* `}` An *EnumDeclaration* introduces a named type (the enum type) and a named value (the enum object) in the containing declaration space. The enum type is a distinct subtype of the Number primitive type. The enum object is a value of an anonymous object type containing a set of properties, all of the enum type, corresponding to the values declared for the enum type in the body of the declaration. The enum object's type furthermore includes a numeric index signature with the signature '[x: number]: string'. @@ -5023,18 +5024,18 @@ enum Color { Red, Green, Blue } declares a subtype of the Number primitive type called 'Color' and introduces a variable 'Color' with a type that corresponds to the declaration ```TypeScript -var Color: { - [x: number]: string; - Red: Color; - Green: Color; - Blue: Color; +var Color: { + [x: number]: string; + Red: Color; + Green: Color; + Blue: Color; }; ``` The numeric index signature reflects a "reverse mapping" that is automatically generated in every enum object, as described in section [9.5](#9.5). The reverse mapping provides a convenient way to obtain the string representation of an enum value. For example ```TypeScript -var c = Color.Red; +var c = Color.Red; console.log(Color[c]); // Outputs "Red" ``` @@ -5042,18 +5043,18 @@ console.log(Color[c]); // Outputs "Red" The body of an enum declaration defines zero or more enum members which are the named values of the enum type. Each enum member has an associated numeric value of the primitive type introduced by the enum declaration. -  *EnumBody:* +  *EnumBody:*    *EnumMemberList* `,`*opt* -  *EnumMemberList:* -   *EnumMember* +  *EnumMemberList:* +   *EnumMember*    *EnumMemberList* `,` *EnumMember* -  *EnumMember:* -   *PropertyName* +  *EnumMember:* +   *PropertyName*    *PropertyName* = *EnumValue* -  *EnumValue:* +  *EnumValue:*    *AssignmentExpression* The *PropertyName* of an enum member cannot be a computed property name ([2.2.3](#2.2.3)). @@ -5079,12 +5080,12 @@ A ***constant enum expression*** is a subset of the expression grammar that can In the example ```TypeScript -enum Test { - A, - B, - C = Math.floor(Math.random() * 1000), - D = 10, - E +enum Test { + A, + B, + C = Math.floor(Math.random() * 1000), + D = 10, + E } ``` @@ -5093,13 +5094,13 @@ enum Test { In the example ```TypeScript -enum Style { - None = 0, - Bold = 1, - Italic = 2, - Underline = 4, - Emphasis = Bold | Italic, - Hyperlink = Bold | Underline +enum Style { + None = 0, + Bold = 1, + Italic = 2, + Underline = 4, + Emphasis = Bold | Italic, + Hyperlink = Bold | Underline } ``` @@ -5120,14 +5121,14 @@ An enum declaration that specifies a `const` modifier is a ***constant enum decl Unlike regular enum declarations, constant enum declarations are completely erased in the emitted JavaScript code. For this reason, it is an error to reference a constant enum object in any other context than a property access that selects one of the enum's members. For example: ```TypeScript -const enum Comparison { - LessThan = -1, - EqualTo = 0, - GreaterThan = 1 +const enum Comparison { + LessThan = -1, + EqualTo = 0, + GreaterThan = 1 } -var x = Comparison.EqualTo; // Ok, replaced with 0 in emitted code -var y = Comparison[Comparison.EqualTo]; // Error +var x = Comparison.EqualTo; // Ok, replaced with 0 in emitted code +var y = Comparison[Comparison.EqualTo]; // Error var z = Comparison; // Error ``` @@ -5138,9 +5139,9 @@ The entire const enum declaration is erased in the emitted JavaScript code. Thus An enum declaration generates JavaScript equivalent to the following: ```TypeScript -var ; -(function () { - +var ; +(function () { + })(||(={})); ``` @@ -5157,11 +5158,11 @@ where *MemberName* is the name of the enum member and *Value* is the assigned co For example, the 'Color' enum example from section [9.1](#9.1) generates the following JavaScript: ```TypeScript -var Color; -(function (Color) { - Color[Color["Red"] = 0] = "Red"; - Color[Color["Green"] = 1] = "Green"; - Color[Color["Blue"] = 2] = "Blue"; +var Color; +(function (Color) { + Color[Color["Red"] = 0] = "Red"; + Color[Color["Green"] = 1] = "Green"; + Color[Color["Blue"] = 2] = "Blue"; })(Color||(Color={})); ``` @@ -5175,11 +5176,11 @@ Namespaces provide a mechanism for organizing code and declarations in hierarchi A namespace declaration introduces a name with a namespace meaning and, in the case of an instantiated namespace, a value meaning in the containing declaration space. -  *NamespaceDeclaration:* +  *NamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *NamespaceBody* `}` -  *IdentifierPath:* -   *BindingIdentifier* +  *IdentifierPath:* +   *BindingIdentifier*    *IdentifierPath* `.` *BindingIdentifier* Namespaces are declared using the `namespace` keyword, but for backward compatibility of earlier versions of TypeScript a `module` keyword can also be used. @@ -5189,15 +5190,15 @@ Namespaces are either ***instantiated*** or ***non-instantiated***. A non-instan When a namespace identifier is referenced as a *NamespaceName* (section [3.8.2](#3.8.2)) it denotes a container of namespace and type names, and when a namespace identifier is referenced as a *PrimaryExpression* (section [4.3](#4.3)) it denotes the singleton namespace instance. For example: ```TypeScript -namespace M { - export interface P { x: number; y: number; } - export var a = 1; +namespace M { + export interface P { x: number; y: number; } + export var a = 1; } -var p: M.P; // M used as NamespaceName -var m = M; // M used as PrimaryExpression -var x1 = M.a; // M used as PrimaryExpression -var x2 = m.a; // Same as M.a +var p: M.P; // M used as NamespaceName +var m = M; // M used as PrimaryExpression +var x1 = M.a; // M used as PrimaryExpression +var x2 = m.a; // Same as M.a var q: m.P; // Error ``` @@ -5208,30 +5209,30 @@ If the declaration of 'M' above had excluded the exported variable 'a', 'M' woul A namespace declaration that specifies an *IdentifierPath* with more than one identifier is equivalent to a series of nested single-identifier namespace declarations where all but the outermost are automatically exported. For example: ```TypeScript -namespace A.B.C { - export var x = 1; +namespace A.B.C { + export var x = 1; } ``` corresponds to ```TypeScript -namespace A { - export namespace B { - export namespace C { - export var x = 1; - } - } +namespace A { + export namespace B { + export namespace C { + export var x = 1; + } + } } ``` The hierarchy formed by namespace and named type names partially mirrors that formed by namespace instances and members. The example ```TypeScript -namespace A { - export namespace B { - export class C { } - } +namespace A { + export namespace B { + export class C { } + } } ``` @@ -5247,49 +5248,49 @@ the two occurrences of 'A.B.C' in fact refer to different entities. It is the co The body of a namespace corresponds to a function that is executed once to initialize the namespace instance. -  *NamespaceBody:* +  *NamespaceBody:*    *NamespaceElementsopt* -  *NamespaceElements:* -   *NamespaceElement* +  *NamespaceElements:* +   *NamespaceElement*    *NamespaceElements* *NamespaceElement* -  *NamespaceElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration -   AmbientDeclaration -   ImportAliasDeclaration +  *NamespaceElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration +   AmbientDeclaration +   ImportAliasDeclaration    ExportNamespaceElement* -  *ExportNamespaceElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportNamespaceElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* ## 10.3 Import Alias Declarations Import alias declarations are used to create local aliases for entities in other namespaces. -  *ImportAliasDeclaration:* +  *ImportAliasDeclaration:*    `import` *BindingIdentifier* `=` *EntityName* `;` -  *EntityName:* -   *NamespaceName* +  *EntityName:* +   *NamespaceName*    *NamespaceName* `.` *IdentifierReference* An *EntityName* consisting of a single identifier is resolved as a *NamespaceName* and is thus required to reference a namespace. The resulting local alias references the given namespace and is itself classified as a namespace. @@ -5299,16 +5300,16 @@ An *EntityName* consisting of more than one identifier is resolved as a *Namespa In the example ```TypeScript -namespace A { - export interface X { s: string } - export var X: X; +namespace A { + export interface X { s: string } + export var X: X; } -namespace B { - interface A { n: number } - import Y = A; // Alias for namespace A - import Z = A.X; // Alias for type and value A.X - var v: Z = Z; +namespace B { + interface A { n: number } + import Y = A; // Alias for namespace A + import Z = A.X; // Alias for type and value A.X + var v: Z = Z; } ``` @@ -5317,13 +5318,13 @@ within 'B', 'Y' is an alias only for namespace 'A' and not the local interface ' If the *NamespaceName* portion of an *EntityName* references an instantiated namespace, the *NamespaceName* is required to reference the namespace instance when evaluated as an expression. In the example ```TypeScript -namespace A { - export interface X { s: string } +namespace A { + export interface X { s: string } } -namespace B { - var A = 1; - import Y = A; +namespace B { + var A = 1; + import Y = A; } ``` @@ -5359,10 +5360,10 @@ In the example ```TypeScript interface A { x: string; } -namespace M { - export interface B { x: A; } - export interface C { x: B; } - export function foo(c: C) { … } +namespace M { + export interface B { x: A; } + export interface C { x: B; } + export function foo(c: C) { … } } ``` @@ -5375,37 +5376,37 @@ Namespaces are "open-ended" and namespace declarations with the same qualified n File a.ts: ```TypeScript -namespace outer { - var local = 1; // Non-exported local variable - export var a = local; // outer.a - export namespace inner { - export var x = 10; // outer.inner.x - } +namespace outer { + var local = 1; // Non-exported local variable + export var a = local; // outer.a + export namespace inner { + export var x = 10; // outer.inner.x + } } ``` File b.ts: ```TypeScript -namespace outer { - var local = 2; // Non-exported local variable - export var b = local; // outer.b - export namespace inner { - export var y = 20; // outer.inner.y - } +namespace outer { + var local = 2; // Non-exported local variable + export var b = local; // outer.b + export namespace inner { + export var y = 20; // outer.inner.y + } } ``` Assuming the two source files are part of the same program, the two declarations will have the global namespace as their common root and will therefore contribute to the same namespace instance, the instance type of which will be: ```TypeScript -{ - a: number; - b: number; - inner: { - x: number; - y: number; - }; +{ + a: number; + b: number; + inner: { + x: number; + y: number; + }; } ``` @@ -5424,24 +5425,24 @@ When merging a non-ambient function or class declaration and a non-ambient names The example ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } -function point(x: number, y: number): Point { - return { x: x, y: y }; +function point(x: number, y: number): Point { + return { x: x, y: y }; } -namespace point { - export var origin = point(0, 0); - export function equals(p1: Point, p2: Point) { - return p1.x == p2.x && p1.y == p2.y; - } +namespace point { + export var origin = point(0, 0); + export function equals(p1: Point, p2: Point) { + return p1.x == p2.x && p1.y == p2.y; + } } -var p1 = point(0, 0); -var p2 = point.origin; +var p1 = point(0, 0); +var p2 = point.origin; var b = point.equals(p1, p2); ``` @@ -5452,9 +5453,9 @@ declares 'point' as a function object with two properties, 'origin' and 'equals' A namespace generates JavaScript code that is equivalent to the following: ```TypeScript -var ; -(function() { - +var ; +(function() { + })(||(={})); ``` @@ -5494,16 +5495,16 @@ TypeScript implements support for ECMAScript 2015 modules and supports down-leve A TypeScript ***program*** consists of one or more source files. -  *SourceFile:* -   *ImplementationSourceFile* +  *SourceFile:* +   *ImplementationSourceFile*    *DeclarationSourceFile* -  *ImplementationSourceFile:* -   *ImplementationScript* +  *ImplementationSourceFile:* +   *ImplementationScript*    *ImplementationModule* -  *DeclarationSourceFile:* -   *DeclarationScript* +  *DeclarationSourceFile:* +   *DeclarationScript*    *DeclarationModule* Source files with extension '.ts' are ***implementation source files*** containing statements and declarations, and source files with extension '.d.ts' are ***declaration source files*** containing declarations only. @@ -5526,46 +5527,46 @@ Any files included as dependencies in turn have their references analyzed in a t Source files that contain no module import or export declarations are classified as ***scripts***. Scripts form the single ***global namespace*** and entities declared in scripts are in scope everywhere in a program. -  *ImplementationScript:* +  *ImplementationScript:*    *ImplementationScriptElementsopt* -  *ImplementationScriptElements:* -   *ImplementationScriptElement* +  *ImplementationScriptElements:* +   *ImplementationScriptElement*    *ImplementationScriptElements* *ImplementationScriptElement* -  *ImplementationScriptElement:* -   *ImplementationElement* +  *ImplementationScriptElement:* +   *ImplementationElement*    *AmbientModuleDeclaration* -  *ImplementationElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *ImplementationElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* -  *DeclarationScript:* +  *DeclarationScript:*    *DeclarationScriptElementsopt* -  *DeclarationScriptElements:* -   *DeclarationScriptElement* +  *DeclarationScriptElements:* +   *DeclarationScriptElement*    *DeclarationScriptElements* *DeclarationScriptElement* -  *DeclarationScriptElement:* -   *DeclarationElement* +  *DeclarationScriptElement:* +   *DeclarationElement*    *AmbientModuleDeclaration* -  *DeclarationElement:* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *DeclarationElement:* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* The initialization order of the scripts that make up the global namespace ultimately depends on the order in which the generated JavaScript files are loaded at run-time (which, for example, may be controlled by <script/> tags that reference the generated JavaScript files). @@ -5574,37 +5575,37 @@ The initialization order of the scripts that make up the global namespace ultima Source files that contain at least one module import or export declaration are considered separate ***modules***. Non-exported entities declared in a module are in scope only in that module, but exported entities can be imported into other modules using import declarations. -  *ImplementationModule:* +  *ImplementationModule:*    *ImplementationModuleElementsopt* -  *ImplementationModuleElements:* -   *ImplementationModuleElement* +  *ImplementationModuleElements:* +   *ImplementationModuleElement*    *ImplementationModuleElements* *ImplementationModuleElement* -  *ImplementationModuleElement:* -   *ImplementationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ImportRequireDeclaration* -   *ExportImplementationElement* -   *ExportDefaultImplementationElement* -   *ExportListDeclaration* +  *ImplementationModuleElement:* +   *ImplementationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ImportRequireDeclaration* +   *ExportImplementationElement* +   *ExportDefaultImplementationElement* +   *ExportListDeclaration*    *ExportAssignment* -  *DeclarationModule:* +  *DeclarationModule:*    *DeclarationModuleElementsopt* -  *DeclarationModuleElements:* -   *DeclarationModuleElement* +  *DeclarationModuleElements:* +   *DeclarationModuleElement*    *DeclarationModuleElements* *DeclarationModuleElement* -  *DeclarationModuleElement:* -   *DeclarationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ExportDeclarationElement* -   *ExportDefaultDeclarationElement* -   *ExportListDeclaration* +  *DeclarationModuleElement:* +   *DeclarationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ExportDeclarationElement* +   *ExportDefaultDeclarationElement* +   *ExportListDeclaration*    *ExportAssignment* Initialization order of modules is determined by the module loader being used and is not specified by the TypeScript language. However, it is generally the case that non-circularly dependent modules are automatically loaded and initialized in the correct order. @@ -5614,13 +5615,13 @@ Modules can additionally be declared using *AmbientModuleDeclarations* in declar Below is an example of two modules written in separate source files: ```TypeScript -// -------- main.ts -------- -import { message } from "./log"; +// -------- main.ts -------- +import { message } from "./log"; message("hello"); -// -------- log.ts -------- -export function message(s: string) { - console.log(s); +// -------- log.ts -------- +export function message(s: string) { + console.log(s); } ``` @@ -5701,7 +5702,7 @@ imports the given module without creating any local bindings (this is useful onl Import require declarations exist for backward compatibility with earlier versions of TypeScript. -  *ImportRequireDeclaration:* +  *ImportRequireDeclaration:*    `import` *BindingIdentifier* `=` `require` `(` *StringLiteral* `)` `;` An import require declaration introduces a local identifier that references a given module. The string literal specified in an import require declaration is interpreted as a module name (section [11.3.1](#11.3.1)). The local identifier introduced by the declaration becomes an alias for, and is classified exactly like, the entity exported from the referenced module. Specifically, if the referenced module contains no export assignment the identifier is classified as a value and a namespace, and if the referenced module contains an export assignment the identifier is classified exactly like the entity named in the export assignment. @@ -5728,30 +5729,30 @@ An export declaration declares one or more exported module members. The exported In the body of a module, a declaration can export the declared entity by including an `export` modifier. -  *ExportImplementationElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportImplementationElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ExportDeclarationElement:* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *AmbientDeclaration* +  *ExportDeclarationElement:* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* In addition to introducing a name in the local declaration space of the module, an exported declaration introduces the same name with the same classification in the module's export declaration space. For example, the declaration ```TypeScript -export function point(x: number, y: number) { - return { x, y }; +export function point(x: number, y: number) { + return { x, y }; } ``` @@ -5761,30 +5762,30 @@ introduces a local name `point` and an exported name `point` that both reference Export default declarations provide short-hand syntax for exporting an entity named `default`. -  *ExportDefaultImplementationElement:* -   `export` `default` *FunctionDeclaration* -   `export` `default` *GeneratorDeclaration* -   `export` `default` *ClassDeclaration* +  *ExportDefaultImplementationElement:* +   `export` `default` *FunctionDeclaration* +   `export` `default` *GeneratorDeclaration* +   `export` `default` *ClassDeclaration*    `export` `default` *AssignmentExpression* `;` -  *ExportDefaultDeclarationElement:* -   `export` `default` *AmbientFunctionDeclaration* -   `export` `default` *AmbientClassDeclaration* +  *ExportDefaultDeclarationElement:* +   `export` `default` *AmbientFunctionDeclaration* +   `export` `default` *AmbientClassDeclaration*    `export` `default` *IdentifierReference* `;` An *ExportDefaultImplementationElement* or *ExportDefaultDeclarationElement* for a function, generator, or class introduces a value named `default`, and in the case of a class, a type named `default`, in the containing module's export declaration space. The declaration may optionally specify a local name for the exported function, generator, or class. For example, the declaration ```TypeScript -export default function point(x: number, y: number) { - return { x, y }; +export default function point(x: number, y: number) { + return { x, y }; } ``` introduces a local name `point` and an exported name `default` that both reference the function. The declaration is effectively equivalent to ```TypeScript -function point(x: number, y: number) { - return { x, y }; +function point(x: number, y: number) { + return { x, y }; } export default point; @@ -5793,8 +5794,8 @@ export default point; which again is equivalent to ```TypeScript -function point(x: number, y: number) { - return { x, y }; +function point(x: number, y: number) { + return { x, y }; } export { point as default }; @@ -5803,13 +5804,13 @@ export { point as default }; An *ExportDefaultImplementationElement* or *ExportDefaultDeclarationElement* for an expression consisting of a single identifier must name an entity declared in the current module or the global namespace. The declaration introduces an entity named `default`, with the same classification as the referenced entity, in the containing module's export declaration space. For example, the declarations ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } -function Point(x: number, y: number): Point { - return { x, y }; +function Point(x: number, y: number): Point { + return { x, y }; } export default Point; @@ -5829,9 +5830,9 @@ introduces an exported value named `default` of type string. An export list declaration exports one or more entities from the current module or a specified module. -  *ExportListDeclaration:* -   `export` `*` *FromClause* `;` -   `export` *ExportClause* *FromClause* `;` +  *ExportListDeclaration:* +   `export` `*` *FromClause* `;` +   `export` *ExportClause* *FromClause* `;`    `export` *ExportClause* `;` An *ExportListDeclaration* without a *FromClause* exports entities from the current module. In a declaration of the form @@ -5882,7 +5883,7 @@ If a module contains an export assignment it is an error for the module to also Export assignments exist for backward compatibility with earlier versions of TypeScript. An export assignment designates a module member as the entity to be exported in place of the module itself. -  *ExportAssignment:* +  *ExportAssignment:*    `export` `=` *IdentifierReference* `;` A module containing an export assignment can be imported using an import require declaration ([11.3.3](#11.3.3)), and the local alias introduced by the import require declaration then takes on all meanings of the identifier named in the export assignment. @@ -5894,9 +5895,9 @@ Assume the following example resides in the file 'point.ts': ```TypeScript export = Point; -class Point { - constructor(public x: number, public y: number) { } - static origin = new Point(0, 0); +class Point { + constructor(public x: number, public y: number) { } + static origin = new Point(0, 0); } ``` @@ -5905,7 +5906,7 @@ When 'point.ts' is imported in another module, the import alias references the e ```TypeScript import Pt = require("./point"); -var p1 = new Pt(10, 20); +var p1 = new Pt(10, 20); var p2 = Pt.origin; ``` @@ -5920,16 +5921,16 @@ The 'main' and 'log' example from section [11.3](#11.3) above generates the foll File main.js: ```TypeScript -var log_1 = require("./log"); +var log_1 = require("./log"); log_1.message("hello"); ``` File log.js: ```TypeScript -function message(s) { - console.log(s); -} +function message(s) { + console.log(s); +} exports.message = message; ``` @@ -5942,29 +5943,29 @@ File geometry.ts: ```TypeScript export interface Point { x: number; y: number }; -export function point(x: number, y: number): Point { - return { x, y }; +export function point(x: number, y: number): Point { + return { x, y }; } ``` File game.ts: ```TypeScript -import * as g from "./geometry"; +import * as g from "./geometry"; let p = g.point(10, 20); ``` The 'game' module references the imported 'geometry' module in an expression (through its alias 'g') and a 'require' call is therefore included in the emitted JavaScript: ```TypeScript -var g = require("./geometry"); +var g = require("./geometry"); var p = g.point(10, 20); ``` Had the 'game' module instead been written to only reference 'geometry' in a type position ```TypeScript -import * as g from "./geometry"; +import * as g from "./geometry"; let p: g.Point = { x: 10, y: 20 }; ``` @@ -5983,19 +5984,19 @@ The "main" and "log" example from above generates the following JavaScript code File main.js: ```TypeScript -define(["require", "exports", "./log"], function(require, exports, log_1) { - log_1.message("hello"); +define(["require", "exports", "./log"], function(require, exports, log_1) { + log_1.message("hello"); } ``` File log.js: ```TypeScript -define(["require", "exports"], function(require, exports) { - function message(s) { - console.log(s); - } - exports.message = message; +define(["require", "exports"], function(require, exports) { + function message(s) { + console.log(s); + } + exports.message = message; } ``` @@ -6011,27 +6012,27 @@ Ambient declarations are used to provide static typing over existing JavaScript Ambient declarations are written using the `declare` keyword and can declare variables, functions, classes, enums, namespaces, or modules. -  *AmbientDeclaration:* -   `declare` *AmbientVariableDeclaration* -   `declare` *AmbientFunctionDeclaration* -   `declare` *AmbientClassDeclaration* -   `declare` *AmbientEnumDeclaration* +  *AmbientDeclaration:* +   `declare` *AmbientVariableDeclaration* +   `declare` *AmbientFunctionDeclaration* +   `declare` *AmbientClassDeclaration* +   `declare` *AmbientEnumDeclaration*    `declare` *AmbientNamespaceDeclaration* ### 12.1.1 Ambient Variable Declarations An ambient variable declaration introduces a variable in the containing declaration space. -  *AmbientVariableDeclaration:* -   `var` *AmbientBindingList* `;` -   `let` *AmbientBindingList* `;` +  *AmbientVariableDeclaration:* +   `var` *AmbientBindingList* `;` +   `let` *AmbientBindingList* `;`    `const` *AmbientBindingList* `;` -  *AmbientBindingList:* -   *AmbientBinding* +  *AmbientBindingList:* +   *AmbientBinding*    *AmbientBindingList* `,` *AmbientBinding* -  *AmbientBinding:* +  *AmbientBinding:*    *BindingIdentifier* *TypeAnnotationopt* An ambient variable declaration may optionally include a type annotation. If no type annotation is present, the variable is assumed to have type Any. @@ -6042,7 +6043,7 @@ An ambient variable declaration does not permit an initializer expression to be An ambient function declaration introduces a function in the containing declaration space. -  *AmbientFunctionDeclaration:* +  *AmbientFunctionDeclaration:*    `function` *BindingIdentifier* *CallSignature* `;` Ambient functions may be overloaded by specifying multiple ambient function declarations with the same name, but it is an error to declare multiple overloads that are considered identical (section [3.11.2](#3.11.2)) or differ only in their return types. @@ -6053,33 +6054,33 @@ Ambient function declarations cannot specify a function bodies and do not permit An ambient class declaration declares a class type and a constructor function in the containing declaration space. -  *AmbientClassDeclaration:* +  *AmbientClassDeclaration:*    `class` *BindingIdentifier* *TypeParametersopt* *ClassHeritage* `{` *AmbientClassBody* `}` -  *AmbientClassBody:* +  *AmbientClassBody:*    *AmbientClassBodyElementsopt* -  *AmbientClassBodyElements:* -   *AmbientClassBodyElement* +  *AmbientClassBodyElements:* +   *AmbientClassBodyElement*    *AmbientClassBodyElements* *AmbientClassBodyElement* -  *AmbientClassBodyElement:* -   *AmbientConstructorDeclaration* -   *AmbientPropertyMemberDeclaration* +  *AmbientClassBodyElement:* +   *AmbientConstructorDeclaration* +   *AmbientPropertyMemberDeclaration*    *IndexSignature* -  *AmbientConstructorDeclaration:* +  *AmbientConstructorDeclaration:*    `constructor` `(` *ParameterListopt* `)` `;` -  *AmbientPropertyMemberDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;` +  *AmbientPropertyMemberDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` ### 12.1.4 Ambient Enum Declarations An ambient enum is grammatically equivalent to a non-ambient enum declaration. -  *AmbientEnumDeclaration:* +  *AmbientEnumDeclaration:*    *EnumDeclaration* Ambient enum declarations differ from non-ambient enum declarations in two ways: @@ -6093,24 +6094,24 @@ Ambient enum declarations are otherwise processed in the same manner as non-ambi An ambient namespace declaration declares a namespace. -  *AmbientNamespaceDeclaration:* +  *AmbientNamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *AmbientNamespaceBody* `}` -  *AmbientNamespaceBody:* +  *AmbientNamespaceBody:*    *AmbientNamespaceElementsopt* -  *AmbientNamespaceElements:* -   *AmbientNamespaceElement* +  *AmbientNamespaceElements:* +   *AmbientNamespaceElement*    *AmbientNamespaceElements* *AmbientNamespaceElement* -  *AmbientNamespaceElement:* -   `export`*opt* *AmbientVariableDeclaration* -   `export`*opt* *AmbientLexicalDeclaration* -   `export`*opt* *AmbientFunctionDeclaration* -   `export`*opt* *AmbientClassDeclaration* -   `export`*opt* *InterfaceDeclaration* -   `export`*opt* *AmbientEnumDeclaration* -   `export`*opt* *AmbientNamespaceDeclaration* +  *AmbientNamespaceElement:* +   `export`*opt* *AmbientVariableDeclaration* +   `export`*opt* *AmbientLexicalDeclaration* +   `export`*opt* *AmbientFunctionDeclaration* +   `export`*opt* *AmbientClassDeclaration* +   `export`*opt* *InterfaceDeclaration* +   `export`*opt* *AmbientEnumDeclaration* +   `export`*opt* *AmbientNamespaceDeclaration*    `export`*opt* *ImportAliasDeclaration* Except for *ImportAliasDeclarations*, *AmbientNamespaceElements* always declare exported entities regardless of whether they include the optional `export` modifier. @@ -6119,7 +6120,7 @@ Except for *ImportAliasDeclarations*, *AmbientNamespaceElements* always declare An *AmbientModuleDeclaration* declares a module. This type of declaration is permitted only at the top level in a source file that contributes to the global namespace (section [11.1](#11.1)). The *StringLiteral* must specify a top-level module name. Relative module names are not permitted. -  *AmbientModuleDeclaration:* +  *AmbientModuleDeclaration:*    `declare` `module` *StringLiteral* `{`  *DeclarationModule* `}` An *ImportRequireDeclaration* in an *AmbientModuleDeclaration* may reference other modules only through top-level module names. Relative module names are not permitted. @@ -6129,21 +6130,21 @@ If an ambient module declaration includes an export assignment, it is an error f Ambient modules are "open-ended" and ambient module declarations with the same string literal name contribute to a single module. For example, the following two declarations of a module 'io' might be located in separate source files. ```TypeScript -declare module "io" { - export function readFile(filename: string): string; +declare module "io" { + export function readFile(filename: string): string; } -declare module "io" { - export function writeFile(filename: string, data: string): void; +declare module "io" { + export function writeFile(filename: string, data: string): void; } ``` This has the same effect as a single combined declaration: ```TypeScript -declare module "io" { - export function readFile(filename: string): string; - export function writeFile(filename: string, data: string): void; +declare module "io" { + export function readFile(filename: string): string; + export function writeFile(filename: string, data: string): void; } ``` @@ -6155,584 +6156,583 @@ This appendix contains a summary of the grammar found in the main document. As d ## A.1 Types -  *TypeParameters:* +  *TypeParameters:*    `<` *TypeParameterList* `>` -  *TypeParameterList:* -   *TypeParameter* +  *TypeParameterList:* +   *TypeParameter*    *TypeParameterList* `,` *TypeParameter* -  *TypeParameter:* +  *TypeParameter:*    *BindingIdentifier* *Constraintopt* -  *Constraint:* +  *Constraint:*    `extends` *Type* -  *TypeArguments:* +  *TypeArguments:*    `<` *TypeArgumentList* `>` -  *TypeArgumentList:* -   *TypeArgument* +  *TypeArgumentList:* +   *TypeArgument*    *TypeArgumentList* `,` *TypeArgument* -  *TypeArgument:* +  *TypeArgument:*    *Type* -  *Type:* -   *UnionOrIntersectionOrPrimaryType* -   *FunctionType* +  *Type:* +   *UnionOrIntersectionOrPrimaryType* +   *FunctionType*    *ConstructorType* -  *UnionOrIntersectionOrPrimaryType:* -   *UnionType* +  *UnionOrIntersectionOrPrimaryType:* +   *UnionType*    *IntersectionOrPrimaryType* -  *IntersectionOrPrimaryType:* -   *IntersectionType* +  *IntersectionOrPrimaryType:* +   *IntersectionType*    *PrimaryType* -  *PrimaryType:* -   *ParenthesizedType* -   *PredefinedType* -   *TypeReference* -   *ObjectType* -   *ArrayType* -   *TupleType* -   *TypeQuery* +  *PrimaryType:* +   *ParenthesizedType* +   *PredefinedType* +   *TypeReference* +   *ObjectType* +   *ArrayType* +   *TupleType* +   *TypeQuery*    *ThisType* -  *ParenthesizedType:* +  *ParenthesizedType:*    `(` *Type* `)` -  *PredefinedType:* -   `any` -   `number` -   `boolean` -   `string` -   `symbol` +  *PredefinedType:* +   `any` +   `number` +   `boolean` +   `string` +   `symbol`    `void` -  *TypeReference:* +  *TypeReference:*    *TypeName* *[no LineTerminator here]* *TypeArgumentsopt* -  *TypeName:* -   *IdentifierReference* +  *TypeName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* -  *NamespaceName:* -   *IdentifierReference* +  *NamespaceName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* -  *ObjectType:* +  *ObjectType:*    `{` *TypeBodyopt* `}` -  *TypeBody:* -   *TypeMemberList* `;`*opt* +  *TypeBody:* +   *TypeMemberList* `;`*opt*    *TypeMemberList* `,`*opt* -  *TypeMemberList:* -   *TypeMember* -   *TypeMemberList* `;` *TypeMember* +  *TypeMemberList:* +   *TypeMember* +   *TypeMemberList* `;` *TypeMember*    *TypeMemberList* `,` *TypeMember* -  *TypeMember:* -   *PropertySignature* -   *CallSignature* -   *ConstructSignature* -   *IndexSignature* +  *TypeMember:* +   *PropertySignature* +   *CallSignature* +   *ConstructSignature* +   *IndexSignature*    *MethodSignature* -  *ArrayType:* +  *ArrayType:*    *PrimaryType* *[no LineTerminator here]* `[` `]` -  *TupleType:* +  *TupleType:*    `[` *TupleElementTypes* `]` -  *TupleElementTypes:* -   *TupleElementType* +  *TupleElementTypes:* +   *TupleElementType*    *TupleElementTypes* `,` *TupleElementType* -  *TupleElementType:* +  *TupleElementType:*    *Type* -  *UnionType:* +  *UnionType:*    *UnionOrIntersectionOrPrimaryType* `|` *IntersectionOrPrimaryType* -  *IntersectionType:* +  *IntersectionType:*    *IntersectionOrPrimaryType* `&` *PrimaryType* -  *FunctionType:* +  *FunctionType:*    *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* -  *ConstructorType:* +  *ConstructorType:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* -  *TypeQuery:* +  *TypeQuery:*    `typeof` *TypeQueryExpression* -  *TypeQueryExpression:* -   *IdentifierReference* +  *TypeQueryExpression:* +   *IdentifierReference*    *TypeQueryExpression* `.` *IdentifierName* -  *ThisType:* +  *ThisType:*    `this` -  *PropertySignature:* +  *PropertySignature:*    *PropertyName* `?`*opt* *TypeAnnotationopt* -  *PropertyName:* -   *IdentifierName* -   *StringLiteral* +  *PropertyName:* +   *IdentifierName* +   *StringLiteral*    *NumericLiteral* -  *TypeAnnotation:* +  *TypeAnnotation:*    `:` *Type* -  *CallSignature:* +  *CallSignature:*    *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* -  *ParameterList:* -   *RequiredParameterList* -   *OptionalParameterList* -   *RestParameter* -   *RequiredParameterList* `,` *OptionalParameterList* -   *RequiredParameterList* `,` *RestParameter* -   *OptionalParameterList* `,` *RestParameter* +  *ParameterList:* +   *RequiredParameterList* +   *OptionalParameterList* +   *RestParameter* +   *RequiredParameterList* `,` *OptionalParameterList* +   *RequiredParameterList* `,` *RestParameter* +   *OptionalParameterList* `,` *RestParameter*    *RequiredParameterList* `,` *OptionalParameterList* `,` *RestParameter* -  *RequiredParameterList:* -   *RequiredParameter* +  *RequiredParameterList:* +   *RequiredParameter*    *RequiredParameterList* `,` *RequiredParameter* -  *RequiredParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* +  *RequiredParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt*    *BindingIdentifier* `:` *StringLiteral* -  *AccessibilityModifier:* -   `public` -   `private` +  *AccessibilityModifier:* +   `public` +   `private`    `protected` -  *BindingIdentifierOrPattern:* -   *BindingIdentifier* +  *BindingIdentifierOrPattern:* +   *BindingIdentifier*    *BindingPattern* -  *OptionalParameterList:* -   *OptionalParameter* +  *OptionalParameterList:* +   *OptionalParameter*    *OptionalParameterList* `,` *OptionalParameter* -  *OptionalParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer* +  *OptionalParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer*    *BindingIdentifier* `?` `:` *StringLiteral* -  *RestParameter:* +  *RestParameter:*    `...` *BindingIdentifier* *TypeAnnotationopt* -  *ConstructSignature:* +  *ConstructSignature:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* -  *IndexSignature:* -   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation* +  *IndexSignature:* +   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation*    `[` *BindingIdentifier* `:` `number` `]` *TypeAnnotation* -  *MethodSignature:* +  *MethodSignature:*    *PropertyName* `?`*opt* *CallSignature* -  *TypeAliasDeclaration:* +  *TypeAliasDeclaration:*    `type` *BindingIdentifier* *TypeParametersopt* `=` *Type* `;` ## A.2 Expressions -  *PropertyDefinition:* *( Modified )* -   *IdentifierReference* -   *CoverInitializedName* -   *PropertyName* `:` *AssignmentExpression* -   *PropertyName* *CallSignature* `{` *FunctionBody* `}` -   *GetAccessor* +  *PropertyDefinition:* *( Modified )* +   *IdentifierReference* +   *CoverInitializedName* +   *PropertyName* `:` *AssignmentExpression* +   *PropertyName* *CallSignature* `{` *FunctionBody* `}` +   *GetAccessor*    *SetAccessor* -  *GetAccessor:* +  *GetAccessor:*    `get` *PropertyName* `(` `)` *TypeAnnotationopt* `{` *FunctionBody* `}` -  *SetAccessor:* +  *SetAccessor:*    `set` *PropertyName* `(` *BindingIdentifierOrPattern* *TypeAnnotationopt* `)` `{` *FunctionBody* `}` -  *FunctionExpression:* *( Modified )* +  *FunctionExpression:* *( Modified )*    `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` -  *ArrowFormalParameters:* *( Modified )* +  *ArrowFormalParameters:* *( Modified )*    *CallSignature* -  *Arguments:* *( Modified )* +  *Arguments:* *( Modified )*    *TypeArgumentsopt* `(` *ArgumentListopt* `)` -  *UnaryExpression:* *( Modified )* -   … +  *UnaryExpression:* *( Modified )* +   …    `<` *Type* `>` *UnaryExpression* ## A.3 Statements -  *Declaration:* *( Modified )* -   … -   *InterfaceDeclaration* -   *TypeAliasDeclaration* +  *Declaration:* *( Modified )* +   … +   *InterfaceDeclaration* +   *TypeAliasDeclaration*    *EnumDeclaration* -  *VariableDeclaration:* *( Modified )* -   *SimpleVariableDeclaration* +  *VariableDeclaration:* *( Modified )* +   *SimpleVariableDeclaration*    *DestructuringVariableDeclaration* -  *SimpleVariableDeclaration:* +  *SimpleVariableDeclaration:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* -  *DestructuringVariableDeclaration:* +  *DestructuringVariableDeclaration:*    *BindingPattern* *TypeAnnotationopt* *Initializer* -  *LexicalBinding:* *( Modified )* -   *SimpleLexicalBinding* +  *LexicalBinding:* *( Modified )* +   *SimpleLexicalBinding*    *DestructuringLexicalBinding* -  *SimpleLexicalBinding:* +  *SimpleLexicalBinding:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* -  *DestructuringLexicalBinding:* +  *DestructuringLexicalBinding:*    *BindingPattern* *TypeAnnotationopt* *Initializeropt* ## A.4 Functions -  *FunctionDeclaration:* *( Modified )* -   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` +  *FunctionDeclaration:* *( Modified )* +   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}`    `function` *BindingIdentifieropt* *CallSignature* `;` ## A.5 Interfaces -  *InterfaceDeclaration:* +  *InterfaceDeclaration:*    `interface` *BindingIdentifier* *TypeParametersopt* *InterfaceExtendsClauseopt* *ObjectType* -  *InterfaceExtendsClause:* +  *InterfaceExtendsClause:*    `extends` *ClassOrInterfaceTypeList* -  *ClassOrInterfaceTypeList:* -   *ClassOrInterfaceType* +  *ClassOrInterfaceTypeList:* +   *ClassOrInterfaceType*    *ClassOrInterfaceTypeList* `,` *ClassOrInterfaceType* -  *ClassOrInterfaceType:* +  *ClassOrInterfaceType:*    *TypeReference* ## A.6 Classes -  *ClassDeclaration:* *( Modified )* +  *ClassDeclaration:* *( Modified )*    `class` *BindingIdentifieropt* *TypeParametersopt* *ClassHeritage* `{` *ClassBody* `}` -  *ClassHeritage:* *( Modified )* +  *ClassHeritage:* *( Modified )*    *ClassExtendsClauseopt* *ImplementsClauseopt* -  *ClassExtendsClause:* +  *ClassExtendsClause:*    `extends`  *ClassType* -  *ClassType:* +  *ClassType:*    *TypeReference* -  *ImplementsClause:* +  *ImplementsClause:*    `implements` *ClassOrInterfaceTypeList* -  *ClassElement:* *( Modified )* -   *ConstructorDeclaration* -   *PropertyMemberDeclaration* +  *ClassElement:* *( Modified )* +   *ConstructorDeclaration* +   *PropertyMemberDeclaration*    *IndexMemberDeclaration* -  *ConstructorDeclaration:* -   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}` +  *ConstructorDeclaration:* +   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}`    *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `;` -  *PropertyMemberDeclaration:* -   *MemberVariableDeclaration* -   *MemberFunctionDeclaration* +  *PropertyMemberDeclaration:* +   *MemberVariableDeclaration* +   *MemberFunctionDeclaration*    *MemberAccessorDeclaration* -  *MemberVariableDeclaration:* +  *MemberVariableDeclaration:*    *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* *Initializeropt* `;` -  *MemberFunctionDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}` +  *MemberFunctionDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` -  *MemberAccessorDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *GetAccessor* +  *MemberAccessorDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *GetAccessor*    *AccessibilityModifieropt* `static`*opt* *SetAccessor* -  *IndexMemberDeclaration:* +  *IndexMemberDeclaration:*    *IndexSignature* `;` ## A.7 Enums -  *EnumDeclaration:* +  *EnumDeclaration:*    `const`*opt* `enum` *BindingIdentifier* `{` *EnumBodyopt* `}` -  *EnumBody:* +  *EnumBody:*    *EnumMemberList* `,`*opt* -  *EnumMemberList:* -   *EnumMember* +  *EnumMemberList:* +   *EnumMember*    *EnumMemberList* `,` *EnumMember* -  *EnumMember:* -   *PropertyName* +  *EnumMember:* +   *PropertyName*    *PropertyName* = *EnumValue* -  *EnumValue:* +  *EnumValue:*    *AssignmentExpression* ## A.8 Namespaces -  *NamespaceDeclaration:* +  *NamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *NamespaceBody* `}` -  *IdentifierPath:* -   *BindingIdentifier* +  *IdentifierPath:* +   *BindingIdentifier*    *IdentifierPath* `.` *BindingIdentifier* -  *NamespaceBody:* +  *NamespaceBody:*    *NamespaceElementsopt* -  *NamespaceElements:* -   *NamespaceElement* +  *NamespaceElements:* +   *NamespaceElement*    *NamespaceElements* *NamespaceElement* -  *NamespaceElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration -   AmbientDeclaration -   ImportAliasDeclaration +  *NamespaceElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration +   AmbientDeclaration +   ImportAliasDeclaration    ExportNamespaceElement* -  *ExportNamespaceElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportNamespaceElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ImportAliasDeclaration:* +  *ImportAliasDeclaration:*    `import` *BindingIdentifier* `=` *EntityName* `;` -  *EntityName:* -   *NamespaceName* +  *EntityName:* +   *NamespaceName*    *NamespaceName* `.` *IdentifierReference* ## A.9 Scripts and Modules -  *SourceFile:* -   *ImplementationSourceFile* +  *SourceFile:* +   *ImplementationSourceFile*    *DeclarationSourceFile* -  *ImplementationSourceFile:* -   *ImplementationScript* +  *ImplementationSourceFile:* +   *ImplementationScript*    *ImplementationModule* -  *DeclarationSourceFile:* -   *DeclarationScript* +  *DeclarationSourceFile:* +   *DeclarationScript*    *DeclarationModule* -  *ImplementationScript:* +  *ImplementationScript:*    *ImplementationScriptElementsopt* -  *ImplementationScriptElements:* -   *ImplementationScriptElement* +  *ImplementationScriptElements:* +   *ImplementationScriptElement*    *ImplementationScriptElements* *ImplementationScriptElement* -  *ImplementationScriptElement:* -   *ImplementationElement* +  *ImplementationScriptElement:* +   *ImplementationElement*    *AmbientModuleDeclaration* -  *ImplementationElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *ImplementationElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* -  *DeclarationScript:* +  *DeclarationScript:*    *DeclarationScriptElementsopt* -  *DeclarationScriptElements:* -   *DeclarationScriptElement* +  *DeclarationScriptElements:* +   *DeclarationScriptElement*    *DeclarationScriptElements* *DeclarationScriptElement* -  *DeclarationScriptElement:* -   *DeclarationElement* +  *DeclarationScriptElement:* +   *DeclarationElement*    *AmbientModuleDeclaration* -  *DeclarationElement:* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *DeclarationElement:* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* -  *ImplementationModule:* +  *ImplementationModule:*    *ImplementationModuleElementsopt* -  *ImplementationModuleElements:* -   *ImplementationModuleElement* +  *ImplementationModuleElements:* +   *ImplementationModuleElement*    *ImplementationModuleElements* *ImplementationModuleElement* -  *ImplementationModuleElement:* -   *ImplementationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ImportRequireDeclaration* -   *ExportImplementationElement* -   *ExportDefaultImplementationElement* -   *ExportListDeclaration* +  *ImplementationModuleElement:* +   *ImplementationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ImportRequireDeclaration* +   *ExportImplementationElement* +   *ExportDefaultImplementationElement* +   *ExportListDeclaration*    *ExportAssignment* -  *DeclarationModule:* +  *DeclarationModule:*    *DeclarationModuleElementsopt* -  *DeclarationModuleElements:* -   *DeclarationModuleElement* +  *DeclarationModuleElements:* +   *DeclarationModuleElement*    *DeclarationModuleElements* *DeclarationModuleElement* -  *DeclarationModuleElement:* -   *DeclarationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ExportDeclarationElement* -   *ExportDefaultDeclarationElement* -   *ExportListDeclaration* +  *DeclarationModuleElement:* +   *DeclarationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ExportDeclarationElement* +   *ExportDefaultDeclarationElement* +   *ExportListDeclaration*    *ExportAssignment* -  *ImportRequireDeclaration:* +  *ImportRequireDeclaration:*    `import` *BindingIdentifier* `=` `require` `(` *StringLiteral* `)` `;` -  *ExportImplementationElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportImplementationElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ExportDeclarationElement:* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *AmbientDeclaration* +  *ExportDeclarationElement:* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ExportDefaultImplementationElement:* -   `export` `default` *FunctionDeclaration* -   `export` `default` *GeneratorDeclaration* -   `export` `default` *ClassDeclaration* +  *ExportDefaultImplementationElement:* +   `export` `default` *FunctionDeclaration* +   `export` `default` *GeneratorDeclaration* +   `export` `default` *ClassDeclaration*    `export` `default` *AssignmentExpression* `;` -  *ExportDefaultDeclarationElement:* -   `export` `default` *AmbientFunctionDeclaration* -   `export` `default` *AmbientClassDeclaration* +  *ExportDefaultDeclarationElement:* +   `export` `default` *AmbientFunctionDeclaration* +   `export` `default` *AmbientClassDeclaration*    `export` `default` *IdentifierReference* `;` -  *ExportListDeclaration:* -   `export` `*` *FromClause* `;` -   `export` *ExportClause* *FromClause* `;` +  *ExportListDeclaration:* +   `export` `*` *FromClause* `;` +   `export` *ExportClause* *FromClause* `;`    `export` *ExportClause* `;` -  *ExportAssignment:* +  *ExportAssignment:*    `export` `=` *IdentifierReference* `;` ## A.10 Ambients -  *AmbientDeclaration:* -   `declare` *AmbientVariableDeclaration* -   `declare` *AmbientFunctionDeclaration* -   `declare` *AmbientClassDeclaration* -   `declare` *AmbientEnumDeclaration* +  *AmbientDeclaration:* +   `declare` *AmbientVariableDeclaration* +   `declare` *AmbientFunctionDeclaration* +   `declare` *AmbientClassDeclaration* +   `declare` *AmbientEnumDeclaration*    `declare` *AmbientNamespaceDeclaration* -  *AmbientVariableDeclaration:* -   `var` *AmbientBindingList* `;` -   `let` *AmbientBindingList* `;` +  *AmbientVariableDeclaration:* +   `var` *AmbientBindingList* `;` +   `let` *AmbientBindingList* `;`    `const` *AmbientBindingList* `;` -  *AmbientBindingList:* -   *AmbientBinding* +  *AmbientBindingList:* +   *AmbientBinding*    *AmbientBindingList* `,` *AmbientBinding* -  *AmbientBinding:* +  *AmbientBinding:*    *BindingIdentifier* *TypeAnnotationopt* -  *AmbientFunctionDeclaration:* +  *AmbientFunctionDeclaration:*    `function` *BindingIdentifier* *CallSignature* `;` -  *AmbientClassDeclaration:* +  *AmbientClassDeclaration:*    `class` *BindingIdentifier* *TypeParametersopt* *ClassHeritage* `{` *AmbientClassBody* `}` -  *AmbientClassBody:* +  *AmbientClassBody:*    *AmbientClassBodyElementsopt* -  *AmbientClassBodyElements:* -   *AmbientClassBodyElement* +  *AmbientClassBodyElements:* +   *AmbientClassBodyElement*    *AmbientClassBodyElements* *AmbientClassBodyElement* -  *AmbientClassBodyElement:* -   *AmbientConstructorDeclaration* -   *AmbientPropertyMemberDeclaration* +  *AmbientClassBodyElement:* +   *AmbientConstructorDeclaration* +   *AmbientPropertyMemberDeclaration*    *IndexSignature* -  *AmbientConstructorDeclaration:* +  *AmbientConstructorDeclaration:*    `constructor` `(` *ParameterListopt* `)` `;` -  *AmbientPropertyMemberDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;` +  *AmbientPropertyMemberDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` -  *AmbientEnumDeclaration:* +  *AmbientEnumDeclaration:*    *EnumDeclaration* -  *AmbientNamespaceDeclaration:* +  *AmbientNamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *AmbientNamespaceBody* `}` -  *AmbientNamespaceBody:* +  *AmbientNamespaceBody:*    *AmbientNamespaceElementsopt* -  *AmbientNamespaceElements:* -   *AmbientNamespaceElement* +  *AmbientNamespaceElements:* +   *AmbientNamespaceElement*    *AmbientNamespaceElements* *AmbientNamespaceElement* -  *AmbientNamespaceElement:* -   `export`*opt* *AmbientVariableDeclaration* -   `export`*opt* *AmbientLexicalDeclaration* -   `export`*opt* *AmbientFunctionDeclaration* -   `export`*opt* *AmbientClassDeclaration* -   `export`*opt* *InterfaceDeclaration* -   `export`*opt* *AmbientEnumDeclaration* -   `export`*opt* *AmbientNamespaceDeclaration* +  *AmbientNamespaceElement:* +   `export`*opt* *AmbientVariableDeclaration* +   `export`*opt* *AmbientLexicalDeclaration* +   `export`*opt* *AmbientFunctionDeclaration* +   `export`*opt* *AmbientClassDeclaration* +   `export`*opt* *InterfaceDeclaration* +   `export`*opt* *AmbientEnumDeclaration* +   `export`*opt* *AmbientNamespaceDeclaration*    `export`*opt* *ImportAliasDeclaration* -  *AmbientModuleDeclaration:* +  *AmbientModuleDeclaration:*    `declare` `module` *StringLiteral* `{`  *DeclarationModule* `}` - diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b09eae7b19b88..3bd0ad47e5922 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18334,7 +18334,7 @@ namespace ts { for (const prop of getPropertiesOfObjectType(type)) { properties[prop.name] = prop; } - checkImplicitPropertyMemberOverrides(type, properties); + checkAugmentedPropertyMemberOverrides(type, properties); } const implementedTypeNodes = getClassImplementsHeritageClauseElements(node); @@ -18388,14 +18388,21 @@ namespace ts { return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined); } - function checkImplicitPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map): void { + function checkAugmentedPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map): void { // If the class does not explicitly declare 'extends Object', // declarations that mask 'Object' members ('toString()', 'hasOwnProperty()', etc...) // are considered here. + + // check is disabled in ambient contexts + if (isInAmbientContext(type.symbol.valueDeclaration)) { + return; + } + const objectType = getSymbol(globals, "Object", SymbolFlags.Type); if (!objectType) { return; } + for (const name in propertiesToCheck) { const derived = getTargetSymbol(propertiesToCheck[name]); const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); @@ -18403,25 +18410,31 @@ namespace ts { if (found) { if (compilerOptions.noImplicitOverride) { const foundSymbol = getTargetSymbol(found); - let detail = "masks Object." + symbolToString(found); - // assert that the type of the derived - // property matches that of the base property. + let errorInfo = chainDiagnosticMessages( + undefined, + Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1, + symbolToString(derived), + symbolToString(found) + ); if (!isPropertyIdenticalTo(derived, foundSymbol)) { - detail += "). The override declaration (" - + typeToString(getTypeOfSymbol(derived)) - + ") also has a different type signature than the original (" - + typeToString(getTypeOfSymbol(foundSymbol)); + errorInfo = chainDiagnosticMessages( + errorInfo, + Diagnostics.Type_0_is_not_assignable_to_type_1, + typeToString(getTypeOfSymbol(derived)), + typeToString(getTypeOfSymbol(foundSymbol)) + ); } - error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1, - symbolToString(derived), detail); + diagnostics.add(createDiagnosticForNodeFromMessageChain(derived.valueDeclaration.name, errorInfo)); } } // No matching property found on the object type. It // is an error for the derived property to falsely // claim 'override'. else if (derivedDeclarationFlags & ModifierFlags.Override) { - error(derived.valueDeclaration.name, Diagnostics.Class_member_0_was_marked_override_but_no_matching_definition_was_found_in_any_supertype_of_1, - symbolToString(derived), typeToString(type)); + error(derived.valueDeclaration.name, + Diagnostics.Class_member_0_was_marked_override_but_no_matching_declaration_was_found_in_any_supertype_of_1, + symbolToString(derived), + typeToString(type)); } } } @@ -18450,6 +18463,8 @@ namespace ts { onlyInDerived[prop.name] = prop; } + const ambient = isInAmbientContext(type.symbol.valueDeclaration); + const baseProperties = getPropertiesOfObjectType(baseType); for (const baseProperty of baseProperties) { const base = getTargetSymbol(baseProperty); @@ -18507,10 +18522,13 @@ namespace ts { // Before accepting the correct case, ensure 'override' is marked if --noImplicitOverride is true. // Abstract members are an exception as override checks are suspended until the implementation solidifies. if (compilerOptions.noImplicitOverride + && !ambient && !(derivedDeclarationFlags & ModifierFlags.Abstract) && !(derivedDeclarationFlags & ModifierFlags.Override)) { - error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1, - symbolToString(derived), "inherited from " + typeToString(baseType)); + error(derived.valueDeclaration.name, + Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1, + symbolToString(derived), + typeToString(baseType)); } continue; @@ -18541,7 +18559,7 @@ namespace ts { } } - checkImplicitPropertyMemberOverrides(type, onlyInDerived); + checkAugmentedPropertyMemberOverrides(type, onlyInDerived); } function isAccessor(kind: SyntaxKind): boolean { @@ -21030,9 +21048,6 @@ namespace ts { else if (flags & ModifierFlags.Async) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "async"); } - else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); - } else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, text); } @@ -21044,6 +21059,14 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "abstract"); } } + else if (flags & ModifierFlags.Override) { + if (modifier.kind === SyntaxKind.PrivateKeyword) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, text, "override"); + } + else { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override"); + } + } flags |= modifierToFlag(modifier.kind); break; @@ -21066,9 +21089,6 @@ namespace ts { else if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); } - else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override"); - } flags |= ModifierFlags.Static; lastStatic = modifier; break; @@ -21131,20 +21151,23 @@ namespace ts { if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "abstract"); } - if (node.kind !== SyntaxKind.ClassDeclaration) { + else if (node.kind !== SyntaxKind.ClassDeclaration) { if (node.kind !== SyntaxKind.MethodDeclaration && node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.GetAccessor && node.kind !== SyntaxKind.SetAccessor) { - return grammarErrorOnNode(modifier, Diagnostics.abstract_modifier_can_only_appear_on_a_class_method_or_property_declaration); + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_class_method_or_property_declaration, "abstract"); } - if (!(node.parent.kind === SyntaxKind.ClassDeclaration && getModifierFlags(node.parent) & ModifierFlags.Abstract)) { + else if (!(node.parent.kind === SyntaxKind.ClassDeclaration && getModifierFlags(node.parent) & ModifierFlags.Abstract)) { return grammarErrorOnNode(modifier, Diagnostics.Abstract_methods_can_only_appear_within_an_abstract_class); } - if (flags & ModifierFlags.Static) { + else if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "abstract"); + } + else if (flags & ModifierFlags.Static) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "abstract"); } - if (flags & ModifierFlags.Private) { + else if (flags & ModifierFlags.Private) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "abstract"); } } @@ -21157,17 +21180,33 @@ namespace ts { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); } else if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override"); + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "static"); } - else if (flags & ModifierFlags.Private) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); + else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); + } + else if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); } else if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override"); } + else if (flags & ModifierFlags.Private) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); + } + else if (node.kind === SyntaxKind.Parameter) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "override"); + } else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override"); } + else if (node.kind !== SyntaxKind.MethodDeclaration && + node.kind !== SyntaxKind.PropertyDeclaration && + node.kind !== SyntaxKind.GetAccessor && + node.kind !== SyntaxKind.SetAccessor) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_class_method_or_property_declaration, "override"); + } + flags |= ModifierFlags.Override; break; @@ -21191,7 +21230,7 @@ namespace ts { if (flags & ModifierFlags.Static) { return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "static"); } - if (flags & ModifierFlags.Abstract) { + else if (flags & ModifierFlags.Abstract) { return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract"); } else if (flags & ModifierFlags.Async) { diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index 78843c58b74bd..af950ac8102bd 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -717,9 +717,6 @@ namespace ts { } function emitClassMemberDeclarationFlags(flags: ModifierFlags) { - if (flags & ModifierFlags.Override) { - write("override "); - } if (flags & ModifierFlags.Private) { write("private "); } @@ -730,6 +727,9 @@ namespace ts { if (flags & ModifierFlags.Static) { write("static "); } + if (flags & ModifierFlags.Override) { + write("override "); + } if (flags & ModifierFlags.Readonly) { write("readonly "); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 857733db7397e..9beda840cd2d1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -767,7 +767,7 @@ "category": "Error", "code": 1241 }, - "'abstract' modifier can only appear on a class, method, or property declaration.": { + "'{0}' modifier can only appear on a class, method, or property declaration.": { "category": "Error", "code": 1242 }, @@ -3291,21 +3291,25 @@ "category": "Error", "code": 90030 }, - "Class member '{0}' was marked 'override', but no matching definition was found in any supertype of '{1}'": { + "Class member '{0}' was marked 'override', but no matching declaration was found in any supertype of '{1}'": { "category": "Error", "code": 90032 }, - "Class member '{0}' must be marked 'override' when noImplicitOverride is enabled ({1})": { + "Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (inherited from {1})": { "category": "Error", "code": 90033 }, + "Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.{1})": { + "category": "Error", + "code": 90034 + }, "override modifier cannot be used with an optional property declaration": { "category": "Error", - "code": 90034 + "code": 90035 }, "All declarations of an override method must be consecutive.": { "category": "Error", - "code": 90035 + "code": 90036 }, "Octal literal types must use ES2015 syntax. Use the syntax '{0}'.": { "category": "Error", diff --git a/tests/baselines/reference/noImplicitOverride.errors.txt b/tests/baselines/reference/noImplicitOverride.errors.txt index 8872952c500b5..4296d22cd732f 100644 --- a/tests/baselines/reference/noImplicitOverride.errors.txt +++ b/tests/baselines/reference/noImplicitOverride.errors.txt @@ -1,12 +1,13 @@ -tests/cases/compiler/noImplicitOverride.ts(10,5): error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) -tests/cases/compiler/noImplicitOverride.ts(11,5): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) -tests/cases/compiler/noImplicitOverride.ts(17,5): error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) -tests/cases/compiler/noImplicitOverride.ts(18,5): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) -tests/cases/compiler/noImplicitOverride.ts(24,5): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty). The override declaration ((prop: string) => number) also has a different type signature than the original ((v: string) => boolean) -tests/cases/compiler/noImplicitOverride.ts(30,12): error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) -tests/cases/compiler/noImplicitOverride.ts(34,9): error TS90033: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) -tests/cases/compiler/noImplicitOverride.ts(42,5): error TS1070: 'override' modifier cannot appear on a type member. -tests/cases/compiler/noImplicitOverride.ts(51,29): error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/noImplicitOverride.ts(11,5): error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) +tests/cases/compiler/noImplicitOverride.ts(12,5): error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) +tests/cases/compiler/noImplicitOverride.ts(18,5): error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.toString) +tests/cases/compiler/noImplicitOverride.ts(19,5): error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) +tests/cases/compiler/noImplicitOverride.ts(25,5): error TS2322: Type '(prop: string) => number' is not assignable to type '(v: string) => boolean'. + Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) +tests/cases/compiler/noImplicitOverride.ts(31,12): error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) +tests/cases/compiler/noImplicitOverride.ts(35,9): error TS90034: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) +tests/cases/compiler/noImplicitOverride.ts(43,5): error TS1070: 'override' modifier cannot appear on a type member. +tests/cases/compiler/noImplicitOverride.ts(52,29): error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) ==== tests/cases/compiler/noImplicitOverride.ts (9 errors) ==== @@ -15,27 +16,28 @@ tests/cases/compiler/noImplicitOverride.ts(51,29): error TS90033: Class member ' get name(): string { return 'Base'; } + getMeaningOfLife(): number { return 42; } public userId: number = 1; } class RejectWhenOverrideMissingOnInheritedMethod extends Object { toString(): string { return 'foo'; }; ~~~~~~~~ -!!! error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +!!! error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) hasOwnProperty(prop: string): boolean { ~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +!!! error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) return super.hasOwnProperty(prop); } } - class RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember { + class RejectWhenOverrideMissingOnAugmentedProperty { toString(): string { return 'foo'; }; ~~~~~~~~ -!!! error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) +!!! error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.toString) hasOwnProperty(prop: string): boolean { ~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) +!!! error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) return false; } } @@ -43,7 +45,8 @@ tests/cases/compiler/noImplicitOverride.ts(51,29): error TS90033: Class member ' class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { hasOwnProperty(prop: string): number { ~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty). The override declaration ((prop: string) => number) also has a different type signature than the original ((v: string) => boolean) +!!! error TS2322: Type '(prop: string) => number' is not assignable to type '(v: string) => boolean'. +!!! error TS2322: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) return -1; } } @@ -51,13 +54,13 @@ tests/cases/compiler/noImplicitOverride.ts(51,29): error TS90033: Class member ' class RejectWhenOverrideMissingOnInheritedProperty extends Base { public userId = 2; ~~~~~~ -!!! error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +!!! error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) } class RejectWhenOverrideMissingOnInheritedAccessor extends Base { get name(): string { return 'foo'; }; ~~~~ -!!! error TS90033: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +!!! error TS90034: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) } interface Shape { @@ -78,6 +81,6 @@ tests/cases/compiler/noImplicitOverride.ts(51,29): error TS90033: Class member ' class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { /** @override */ public userId: number = 2; ~~~~~~ -!!! error TS90033: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +!!! error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) } \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitOverride.js b/tests/baselines/reference/noImplicitOverride.js index ca1cee5d662e6..dba3cecbe7a44 100644 --- a/tests/baselines/reference/noImplicitOverride.js +++ b/tests/baselines/reference/noImplicitOverride.js @@ -4,6 +4,7 @@ class Base { get name(): string { return 'Base'; } + getMeaningOfLife(): number { return 42; } public userId: number = 1; } @@ -14,7 +15,7 @@ class RejectWhenOverrideMissingOnInheritedMethod extends Object { } } -class RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember { +class RejectWhenOverrideMissingOnAugmentedProperty { toString(): string { return 'foo'; }; hasOwnProperty(prop: string): boolean { return false; @@ -54,11 +55,16 @@ class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { //// [noImplicitOverride.js] -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -}; +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var Base = (function () { function Base() { this.userId = 1; @@ -70,12 +76,13 @@ var Base = (function () { enumerable: true, configurable: true }); + Base.prototype.getMeaningOfLife = function () { return 42; }; return Base; }()); var RejectWhenOverrideMissingOnInheritedMethod = (function (_super) { __extends(RejectWhenOverrideMissingOnInheritedMethod, _super); function RejectWhenOverrideMissingOnInheritedMethod() { - return _super.apply(this, arguments) || this; + return _super !== null && _super.apply(this, arguments) || this; } RejectWhenOverrideMissingOnInheritedMethod.prototype.toString = function () { return 'foo'; }; ; @@ -84,15 +91,15 @@ var RejectWhenOverrideMissingOnInheritedMethod = (function (_super) { }; return RejectWhenOverrideMissingOnInheritedMethod; }(Object)); -var RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember = (function () { - function RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember() { +var RejectWhenOverrideMissingOnAugmentedProperty = (function () { + function RejectWhenOverrideMissingOnAugmentedProperty() { } - RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember.prototype.toString = function () { return 'foo'; }; + RejectWhenOverrideMissingOnAugmentedProperty.prototype.toString = function () { return 'foo'; }; ; - RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember.prototype.hasOwnProperty = function (prop) { + RejectWhenOverrideMissingOnAugmentedProperty.prototype.hasOwnProperty = function (prop) { return false; }; - return RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember; + return RejectWhenOverrideMissingOnAugmentedProperty; }()); var RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember = (function () { function RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember() { @@ -105,7 +112,7 @@ var RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember = (function var RejectWhenOverrideMissingOnInheritedProperty = (function (_super) { __extends(RejectWhenOverrideMissingOnInheritedProperty, _super); function RejectWhenOverrideMissingOnInheritedProperty() { - var _this = _super.apply(this, arguments) || this; + var _this = _super !== null && _super.apply(this, arguments) || this; _this.userId = 2; return _this; } @@ -114,7 +121,7 @@ var RejectWhenOverrideMissingOnInheritedProperty = (function (_super) { var RejectWhenOverrideMissingOnInheritedAccessor = (function (_super) { __extends(RejectWhenOverrideMissingOnInheritedAccessor, _super); function RejectWhenOverrideMissingOnInheritedAccessor() { - return _super.apply(this, arguments) || this; + return _super !== null && _super.apply(this, arguments) || this; } Object.defineProperty(RejectWhenOverrideMissingOnInheritedAccessor.prototype, "name", { get: function () { return 'foo'; }, @@ -127,7 +134,7 @@ var RejectWhenOverrideMissingOnInheritedAccessor = (function (_super) { var FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation = (function (_super) { __extends(FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation, _super); function FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation() { - var _this = _super.apply(this, arguments) || this; + var _this = _super !== null && _super.apply(this, arguments) || this; /** @override */ _this.userId = 2; return _this; } diff --git a/tests/baselines/reference/overrideKeyword.errors.txt b/tests/baselines/reference/overrideKeyword.errors.txt deleted file mode 100644 index 55a852ae9eb98..0000000000000 --- a/tests/baselines/reference/overrideKeyword.errors.txt +++ /dev/null @@ -1,147 +0,0 @@ -tests/cases/compiler/overrideKeyword.ts(4,12): error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) -tests/cases/compiler/overrideKeyword.ts(14,5): error TS90033: Class member 'toStringAbstract' must be marked 'override' when noImplicitOverride is enabled (inherited from AbstractBase) -tests/cases/compiler/overrideKeyword.ts(25,5): error TS90034: override modifier cannot be used with an optional property declaration -tests/cases/compiler/overrideKeyword.ts(29,14): error TS1243: 'abstract' modifier cannot be used with 'override' modifier. -tests/cases/compiler/overrideKeyword.ts(33,14): error TS1243: 'static' modifier cannot be used with 'override' modifier. -tests/cases/compiler/overrideKeyword.ts(36,7): error TS2415: Class 'RejectWhenAttemptToOverridePrivateMethod' incorrectly extends base class 'Base'. - Types have separate declarations of a private property 'toStringPrivate'. -tests/cases/compiler/overrideKeyword.ts(37,13): error TS1243: 'private' modifier cannot be used with 'override' modifier. -tests/cases/compiler/overrideKeyword.ts(41,21): error TS1030: 'override' modifier already seen. -tests/cases/compiler/overrideKeyword.ts(45,14): error TS1029: 'public' modifier must precede 'override' modifier. -tests/cases/compiler/overrideKeyword.ts(49,21): error TS90032: Class member 'iDontExist' was marked 'override', but no matching definition was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' -tests/cases/compiler/overrideKeyword.ts(52,7): error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. - Types of property 'getMeaningOfLife' are incompatible. - Type '() => string' is not assignable to type '() => number'. - Type 'string' is not assignable to type 'number'. -tests/cases/compiler/overrideKeyword.ts(57,18): error TS2699: Accessors must both be override or non-override. -tests/cases/compiler/overrideKeyword.ts(60,9): error TS2699: Accessors must both be override or non-override. -tests/cases/compiler/overrideKeyword.ts(67,14): error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) -tests/cases/compiler/overrideKeyword.ts(71,12): error TS90033: Class member 'getMeaningOfLife' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) -tests/cases/compiler/overrideKeyword.ts(75,14): error TS90033: Class member 'propertyIsEnumerable' must be marked 'override' when noImplicitOverride is enabled (masks Object.propertyIsEnumerable) - - -==== tests/cases/compiler/overrideKeyword.ts (16 errors) ==== - - abstract class AbstractBase { - static toStringStatic(): string { return 'static member'; } - public toString(): string { return 'instance member'; }; - ~~~~~~~~ -!!! error TS90033: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (masks Object.toString) - abstract toStringAbstract(): string; - private toStringPrivate(): string { return 'private member'; } - getMeaningOfLife(): number { return 42; } - public wasDisposed?: boolean; - } - - class Base extends AbstractBase { - private name_: string; - - toStringAbstract(): string { return 'implementation of abstract member'; }; - ~~~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'toStringAbstract' must be marked 'override' when noImplicitOverride is enabled (inherited from AbstractBase) - - get name() { - return this.name_; - } - - set name(name: string) { - this.name_ = name; - } - - // override cannot be used with optional property. - public override wasDisposed?: boolean; - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS90034: override modifier cannot be used with an optional property declaration - } - - abstract class RejectWhenAttemptToOverrideAbstractMethod extends AbstractBase { - abstract override toStringAbstract(): string; - ~~~~~~~~ -!!! error TS1243: 'abstract' modifier cannot be used with 'override' modifier. - } - - class RejectWhenAttemptToOverrideStaticMethod extends Base { - override static toStringStatic() { return ''; }; - ~~~~~~ -!!! error TS1243: 'static' modifier cannot be used with 'override' modifier. - } - - class RejectWhenAttemptToOverridePrivateMethod extends Base { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2415: Class 'RejectWhenAttemptToOverridePrivateMethod' incorrectly extends base class 'Base'. -!!! error TS2415: Types have separate declarations of a private property 'toStringPrivate'. - private override toStringPrivate() { return ''; }; - ~~~~~~~~ -!!! error TS1243: 'private' modifier cannot be used with 'override' modifier. - } - - class RejectWhenOverrideIsRepeated extends Base { - public override override toString() { return ''; }; - ~~~~~~~~ -!!! error TS1030: 'override' modifier already seen. - } - - class RejectWhenOverridePrecedesAccessModifier extends Base { - override public toString() { return ''; }; - ~~~~~~ -!!! error TS1029: 'public' modifier must precede 'override' modifier. - } - - class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { - public override iDontExist() { return ''; }; - ~~~~~~~~~~ -!!! error TS90032: Class member 'iDontExist' was marked 'override', but no matching definition was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' - } - - class RejectWhenOverrideHasMismatchedType extends Base { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. -!!! error TS2415: Types of property 'getMeaningOfLife' are incompatible. -!!! error TS2415: Type '() => string' is not assignable to type '() => number'. -!!! error TS2415: Type 'string' is not assignable to type 'number'. - override getMeaningOfLife(): string { return 'forty-two'; }; - } - - class RejectWhenAccessorNotBothOverride extends Base { - override get name() { - ~~~~ -!!! error TS2699: Accessors must both be override or non-override. - return 'hardcoded value'; - } - set name(n: string) { - ~~~~ -!!! error TS2699: Accessors must both be override or non-override. - } - } - - /* @mhegazy: is this an appropriate test for consecutive declarations? */ - class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { - - override hasOwnProperty(prop: string): boolean { - ~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (masks Object.hasOwnProperty) - return super.hasOwnProperty(prop); - } - - public getMeaningOfLife(): number { - ~~~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'getMeaningOfLife' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) - return 42; - } - - override propertyIsEnumerable(prop: string): boolean { - ~~~~~~~~~~~~~~~~~~~~ -!!! error TS90033: Class member 'propertyIsEnumerable' must be marked 'override' when noImplicitOverride is enabled (masks Object.propertyIsEnumerable) - return super.propertyIsEnumerable(prop); - } - - } - - class AcceptWhenOverrideFollowsAccessModifier extends Base { - public override toString() { return ''; }; - } - - class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { - public override getMeaningOfLife(): number { return 12; }; - } - \ No newline at end of file diff --git a/tests/baselines/reference/overrideKeyword.js b/tests/baselines/reference/overrideKeyword.js deleted file mode 100644 index 84621b2bbd143..0000000000000 --- a/tests/baselines/reference/overrideKeyword.js +++ /dev/null @@ -1,237 +0,0 @@ -//// [overrideKeyword.ts] - -abstract class AbstractBase { - static toStringStatic(): string { return 'static member'; } - public toString(): string { return 'instance member'; }; - abstract toStringAbstract(): string; - private toStringPrivate(): string { return 'private member'; } - getMeaningOfLife(): number { return 42; } - public wasDisposed?: boolean; -} - -class Base extends AbstractBase { - private name_: string; - - toStringAbstract(): string { return 'implementation of abstract member'; }; - - get name() { - return this.name_; - } - - set name(name: string) { - this.name_ = name; - } - - // override cannot be used with optional property. - public override wasDisposed?: boolean; -} - -abstract class RejectWhenAttemptToOverrideAbstractMethod extends AbstractBase { - abstract override toStringAbstract(): string; -} - -class RejectWhenAttemptToOverrideStaticMethod extends Base { - override static toStringStatic() { return ''; }; -} - -class RejectWhenAttemptToOverridePrivateMethod extends Base { - private override toStringPrivate() { return ''; }; -} - -class RejectWhenOverrideIsRepeated extends Base { - public override override toString() { return ''; }; -} - -class RejectWhenOverridePrecedesAccessModifier extends Base { - override public toString() { return ''; }; -} - -class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { - public override iDontExist() { return ''; }; -} - -class RejectWhenOverrideHasMismatchedType extends Base { - override getMeaningOfLife(): string { return 'forty-two'; }; -} - -class RejectWhenAccessorNotBothOverride extends Base { - override get name() { - return 'hardcoded value'; - } - set name(n: string) { - } -} - -/* @mhegazy: is this an appropriate test for consecutive declarations? */ -class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { - - override hasOwnProperty(prop: string): boolean { - return super.hasOwnProperty(prop); - } - - public getMeaningOfLife(): number { - return 42; - } - - override propertyIsEnumerable(prop: string): boolean { - return super.propertyIsEnumerable(prop); - } - -} - -class AcceptWhenOverrideFollowsAccessModifier extends Base { - public override toString() { return ''; }; -} - -class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { - public override getMeaningOfLife(): number { return 12; }; -} - - -//// [overrideKeyword.js] -var __extends = (this && this.__extends) || function (d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); -}; -var AbstractBase = (function () { - function AbstractBase() { - } - AbstractBase.toStringStatic = function () { return 'static member'; }; - AbstractBase.prototype.toString = function () { return 'instance member'; }; - ; - AbstractBase.prototype.toStringPrivate = function () { return 'private member'; }; - AbstractBase.prototype.getMeaningOfLife = function () { return 42; }; - return AbstractBase; -}()); -var Base = (function (_super) { - __extends(Base, _super); - function Base() { - return _super.apply(this, arguments) || this; - } - Base.prototype.toStringAbstract = function () { return 'implementation of abstract member'; }; - ; - Object.defineProperty(Base.prototype, "name", { - get: function () { - return this.name_; - }, - set: function (name) { - this.name_ = name; - }, - enumerable: true, - configurable: true - }); - return Base; -}(AbstractBase)); -var RejectWhenAttemptToOverrideAbstractMethod = (function (_super) { - __extends(RejectWhenAttemptToOverrideAbstractMethod, _super); - function RejectWhenAttemptToOverrideAbstractMethod() { - return _super.apply(this, arguments) || this; - } - return RejectWhenAttemptToOverrideAbstractMethod; -}(AbstractBase)); -var RejectWhenAttemptToOverrideStaticMethod = (function (_super) { - __extends(RejectWhenAttemptToOverrideStaticMethod, _super); - function RejectWhenAttemptToOverrideStaticMethod() { - return _super.apply(this, arguments) || this; - } - RejectWhenAttemptToOverrideStaticMethod.toStringStatic = function () { return ''; }; - ; - return RejectWhenAttemptToOverrideStaticMethod; -}(Base)); -var RejectWhenAttemptToOverridePrivateMethod = (function (_super) { - __extends(RejectWhenAttemptToOverridePrivateMethod, _super); - function RejectWhenAttemptToOverridePrivateMethod() { - return _super.apply(this, arguments) || this; - } - RejectWhenAttemptToOverridePrivateMethod.prototype.toStringPrivate = function () { return ''; }; - ; - return RejectWhenAttemptToOverridePrivateMethod; -}(Base)); -var RejectWhenOverrideIsRepeated = (function (_super) { - __extends(RejectWhenOverrideIsRepeated, _super); - function RejectWhenOverrideIsRepeated() { - return _super.apply(this, arguments) || this; - } - RejectWhenOverrideIsRepeated.prototype.toString = function () { return ''; }; - ; - return RejectWhenOverrideIsRepeated; -}(Base)); -var RejectWhenOverridePrecedesAccessModifier = (function (_super) { - __extends(RejectWhenOverridePrecedesAccessModifier, _super); - function RejectWhenOverridePrecedesAccessModifier() { - return _super.apply(this, arguments) || this; - } - RejectWhenOverridePrecedesAccessModifier.prototype.toString = function () { return ''; }; - ; - return RejectWhenOverridePrecedesAccessModifier; -}(Base)); -var RejectWhenOverrideMarkedOnNonInheritedMember = (function (_super) { - __extends(RejectWhenOverrideMarkedOnNonInheritedMember, _super); - function RejectWhenOverrideMarkedOnNonInheritedMember() { - return _super.apply(this, arguments) || this; - } - RejectWhenOverrideMarkedOnNonInheritedMember.prototype.iDontExist = function () { return ''; }; - ; - return RejectWhenOverrideMarkedOnNonInheritedMember; -}(Base)); -var RejectWhenOverrideHasMismatchedType = (function (_super) { - __extends(RejectWhenOverrideHasMismatchedType, _super); - function RejectWhenOverrideHasMismatchedType() { - return _super.apply(this, arguments) || this; - } - RejectWhenOverrideHasMismatchedType.prototype.getMeaningOfLife = function () { return 'forty-two'; }; - ; - return RejectWhenOverrideHasMismatchedType; -}(Base)); -var RejectWhenAccessorNotBothOverride = (function (_super) { - __extends(RejectWhenAccessorNotBothOverride, _super); - function RejectWhenAccessorNotBothOverride() { - return _super.apply(this, arguments) || this; - } - Object.defineProperty(RejectWhenAccessorNotBothOverride.prototype, "name", { - get: function () { - return 'hardcoded value'; - }, - set: function (n) { - }, - enumerable: true, - configurable: true - }); - return RejectWhenAccessorNotBothOverride; -}(Base)); -/* @mhegazy: is this an appropriate test for consecutive declarations? */ -var RejectWhenOverrideDeclarationsAreNotConsecutive = (function (_super) { - __extends(RejectWhenOverrideDeclarationsAreNotConsecutive, _super); - function RejectWhenOverrideDeclarationsAreNotConsecutive() { - return _super.apply(this, arguments) || this; - } - RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.hasOwnProperty = function (prop) { - return _super.prototype.hasOwnProperty.call(this, prop); - }; - RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.getMeaningOfLife = function () { - return 42; - }; - RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.propertyIsEnumerable = function (prop) { - return _super.prototype.propertyIsEnumerable.call(this, prop); - }; - return RejectWhenOverrideDeclarationsAreNotConsecutive; -}(Base)); -var AcceptWhenOverrideFollowsAccessModifier = (function (_super) { - __extends(AcceptWhenOverrideFollowsAccessModifier, _super); - function AcceptWhenOverrideFollowsAccessModifier() { - return _super.apply(this, arguments) || this; - } - AcceptWhenOverrideFollowsAccessModifier.prototype.toString = function () { return ''; }; - ; - return AcceptWhenOverrideFollowsAccessModifier; -}(Base)); -var AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass = (function (_super) { - __extends(AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass, _super); - function AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass() { - return _super.apply(this, arguments) || this; - } - AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass.prototype.getMeaningOfLife = function () { return 12; }; - ; - return AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass; -}(Base)); diff --git a/tests/baselines/reference/overrideKeyword.symbols b/tests/baselines/reference/overrideKeyword.symbols deleted file mode 100644 index 310ce18f6f286..0000000000000 --- a/tests/baselines/reference/overrideKeyword.symbols +++ /dev/null @@ -1,17 +0,0 @@ -=== tests/cases/compiler/overrideKeyword.ts === -class Base { ->Base : Symbol(Base, Decl(overrideKeyword.ts, 0, 0)) - - public toString() { return "base"; }; ->toString : Symbol(Base.toString, Decl(overrideKeyword.ts, 0, 12)) -} - -class Derived extends Base { ->Derived : Symbol(Derived, Decl(overrideKeyword.ts, 2, 1)) ->Base : Symbol(Base, Decl(overrideKeyword.ts, 0, 0)) - - /** @override */ - public override toString() { return "derived"; }; ->toString : Symbol(Derived.toString, Decl(overrideKeyword.ts, 4, 28)) -} - diff --git a/tests/baselines/reference/overrideKeyword.types b/tests/baselines/reference/overrideKeyword.types deleted file mode 100644 index 9748e915a7ce4..0000000000000 --- a/tests/baselines/reference/overrideKeyword.types +++ /dev/null @@ -1,19 +0,0 @@ -=== tests/cases/compiler/overrideKeyword.ts === -class Base { ->Base : Base - - public toString() { return "base"; }; ->toString : () => string ->"base" : "base" -} - -class Derived extends Base { ->Derived : Derived ->Base : Base - - /** @override */ - public override toString() { return "derived"; }; ->toString : () => string ->"derived" : "derived" -} - diff --git a/tests/baselines/reference/overrideKeywordEs5.errors.txt b/tests/baselines/reference/overrideKeywordEs5.errors.txt new file mode 100644 index 0000000000000..7acba2cd39852 --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs5.errors.txt @@ -0,0 +1,197 @@ +tests/cases/compiler/overrideKeywordEs5.ts(29,72): error TS1029: 'public' modifier must precede 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(30,75): error TS1029: 'protected' modifier must precede 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(31,70): error TS1029: 'override' modifier must precede 'static' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(33,74): error TS1029: 'override' modifier must precede 'readonly' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(37,21): error TS1030: 'override' modifier already seen. +tests/cases/compiler/overrideKeywordEs5.ts(41,7): error TS2415: Class 'RejectWhenOverridePrivateMethod' incorrectly extends base class 'Base'. + Types have separate declarations of a private property 'toStringPrivate'. +tests/cases/compiler/overrideKeywordEs5.ts(42,13): error TS1243: 'private' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(43,14): error TS1243: 'private' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(48,14): error TS1243: 'abstract' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(49,14): error TS1243: 'override' modifier cannot be used with 'abstract' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(64,7): error TS2417: Class static side 'typeof RejectWhenOverrideChangesAccessModifier' incorrectly extends base class static side 'typeof Base'. + Property 'toStringStatic' is protected in type 'typeof RejectWhenOverrideChangesAccessModifier' but public in type 'typeof Base'. +tests/cases/compiler/overrideKeywordEs5.ts(76,5): error TS90035: override modifier cannot be used with an optional property declaration +tests/cases/compiler/overrideKeywordEs5.ts(81,18): error TS2699: Accessors must both be override or non-override. +tests/cases/compiler/overrideKeywordEs5.ts(82,18): error TS2699: Accessors must both be override or non-override. +tests/cases/compiler/overrideKeywordEs5.ts(87,21): error TS90032: Class member 'iDontExist' was marked 'override', but no matching declaration was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' +tests/cases/compiler/overrideKeywordEs5.ts(92,7): error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. + Types of property 'getMeaningOfLife' are incompatible. + Type '() => string' is not assignable to type '() => number'. + Type 'string' is not assignable to type 'number'. +tests/cases/compiler/overrideKeywordEs5.ts(98,21): error TS1090: 'override' modifier cannot appear on a parameter. +tests/cases/compiler/overrideKeywordEs5.ts(102,1): error TS1044: 'override' modifier cannot appear on a module or namespace element. +tests/cases/compiler/overrideKeywordEs5.ts(103,1): error TS1044: 'override' modifier cannot appear on a module or namespace element. +tests/cases/compiler/overrideKeywordEs5.ts(107,5): error TS1070: 'override' modifier cannot appear on a type member. + + +==== tests/cases/compiler/overrideKeywordEs5.ts (20 errors) ==== + + abstract class AbstractBase { + readonly id: string; + public wasDisposed?: boolean; + private name_: string; + get name() { return this.name_; } + set name(name: string) { this.name_ = name; } + + static toStringStatic(): string { return 'static'; } + public toStringPublic(): string { return 'public'; }; + protected toStringProtected(): string { return 'protected'; } + private toStringPrivate(): string { return 'private'; } + private toStringPrivate2(): string { return 'private2'; } + abstract toStringAbstract(): string; + abstract toStringAbstract2(): string; + + getMeaningOfLife(): number { return 42; } + } + + class Base extends AbstractBase { + override toStringAbstract(): string { return 'implemented'; } + override toStringAbstract2(): string { return 'implemented2'; } + } + + // The expected order of modifiers: + // + // [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier + // + class RejectWhenOverridePrecedesPublicModifier extends Base { override public toStringPublic() { return ''; }; } + ~~~~~~ +!!! error TS1029: 'public' modifier must precede 'override' modifier. + class RejectWhenOverridePrecedesProtectedModifier extends Base { override protected toStringProtected() { return ''; }; } + ~~~~~~~~~ +!!! error TS1029: 'protected' modifier must precede 'override' modifier. + class RejectWhenStaticPrecedesOverrideModifier extends Base { static override toStringStatic() { return ''; }; } + ~~~~~~~~ +!!! error TS1029: 'override' modifier must precede 'static' modifier. + class AcceptWhenOverrideFollowsAccessModifier extends Base { public override toStringPublic() { return ''; } } + class RejectWhenReadonlyPrecedesOverrideModifier extends Base { readonly override id: string; } + ~~~~~~~~ +!!! error TS1029: 'override' modifier must precede 'readonly' modifier. + + // Modifiers should never be repeated + class RejectWhenOverrideIsRepeated extends Base { + public override override toStringPublic() { return ''; } + ~~~~~~~~ +!!! error TS1030: 'override' modifier already seen. + } + + // You cannot override a private method + class RejectWhenOverridePrivateMethod extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2415: Class 'RejectWhenOverridePrivateMethod' incorrectly extends base class 'Base'. +!!! error TS2415: Types have separate declarations of a private property 'toStringPrivate'. + private override toStringPrivate() { return ''; } + ~~~~~~~~ +!!! error TS1243: 'private' modifier cannot be used with 'override' modifier. + override private toStringPrivate2() { return ''; } + ~~~~~~~ +!!! error TS1243: 'private' modifier cannot be used with 'override' modifier. + } + + // Override and abstract on methods are orthogonal, should never be used together + abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { + abstract override toStringAbstract(): string; + ~~~~~~~~ +!!! error TS1243: 'abstract' modifier cannot be used with 'override' modifier. + override abstract toStringAbstract2(): string; + ~~~~~~~~ +!!! error TS1243: 'override' modifier cannot be used with 'abstract' modifier. + } + + // Acceptable to provide an override implementation in an abstract class however + abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { + override toStringAbstract(): string { return 'implemented in abstract class'; } + } + + // Override checks are allowed on static methods + class AcceptWhenOverrideStaticMethod extends Base { + override static toStringStatic() { return 'static'; } + } + + // Compiler already checks for access modifier narrowing, + // override does not alter these semantics. + class RejectWhenOverrideChangesAccessModifier extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2417: Class static side 'typeof RejectWhenOverrideChangesAccessModifier' incorrectly extends base class static side 'typeof Base'. +!!! error TS2417: Property 'toStringStatic' is protected in type 'typeof RejectWhenOverrideChangesAccessModifier' but public in type 'typeof Base'. + protected override static toStringStatic() { return 'member is now protected'; } + } + + // Compiler should be able to traverse multiple levels of inheritance + // to assess for overriden members (already does this). + class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + override getMeaningOfLife(): number { return 12; } + } + + // Override cannot be used with optional property. + class RejectWhenOverrideOptionalProperty extends Base { + public override wasDisposed?: boolean; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS90035: override modifier cannot be used with an optional property declaration + } + + // If one accessor is marked override, they both should be. + class RejectWhenAccessorNotBothOverride extends Base { + override get name() { return ''; } + ~~~~ +!!! error TS2699: Accessors must both be override or non-override. + /* */ set name(n: string) {} + ~~~~ +!!! error TS2699: Accessors must both be override or non-override. + } + + // Compiler should detect when override member is not inherited or augmented + class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + public override iDontExist() { return ''; } + ~~~~~~~~~~ +!!! error TS90032: Class member 'iDontExist' was marked 'override', but no matching declaration was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' + } + + // Compiler already detects overriden assignability mismatches, + // override keyword does not change these semantics + class RejectWhenOverrideHasMismatchedType extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. +!!! error TS2415: Types of property 'getMeaningOfLife' are incompatible. +!!! error TS2415: Type '() => string' is not assignable to type '() => number'. +!!! error TS2415: Type 'string' is not assignable to type 'number'. + override getMeaningOfLife(): string { return 'the meaning of life is a number, not a string'; } + } + + // Override is not be used on parameters + class RejectWhenOverrideIsOnAParameter { + public sayHello(override name: string) { return 'hi'; } + ~~~~~~~~ +!!! error TS1090: 'override' modifier cannot appear on a parameter. + } + + // Override is not used on class... + override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } + ~~~~~~~~ +!!! error TS1044: 'override' modifier cannot appear on a module or namespace element. + override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } + ~~~~~~~~ +!!! error TS1044: 'override' modifier cannot appear on a module or namespace element. + + //... or interface declarations + interface RejectWhenOverrideInAnInterface { + override sayHello(name: string); + ~~~~~~~~ +!!! error TS1070: 'override' modifier cannot appear on a type member. + } + + /* @mhegazy: is this an appropriate test for consecutive declarations? */ + class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + override hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } + + public getMeaningOfLife(): number { + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { + return super.propertyIsEnumerable(prop); + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/overrideKeywordEs5.js b/tests/baselines/reference/overrideKeywordEs5.js new file mode 100644 index 0000000000000..c676203528323 --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs5.js @@ -0,0 +1,435 @@ +//// [overrideKeywordEs5.ts] + +abstract class AbstractBase { + readonly id: string; + public wasDisposed?: boolean; + private name_: string; + get name() { return this.name_; } + set name(name: string) { this.name_ = name; } + + static toStringStatic(): string { return 'static'; } + public toStringPublic(): string { return 'public'; }; + protected toStringProtected(): string { return 'protected'; } + private toStringPrivate(): string { return 'private'; } + private toStringPrivate2(): string { return 'private2'; } + abstract toStringAbstract(): string; + abstract toStringAbstract2(): string; + + getMeaningOfLife(): number { return 42; } +} + +class Base extends AbstractBase { + override toStringAbstract(): string { return 'implemented'; } + override toStringAbstract2(): string { return 'implemented2'; } +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenOverridePrecedesPublicModifier extends Base { override public toStringPublic() { return ''; }; } +class RejectWhenOverridePrecedesProtectedModifier extends Base { override protected toStringProtected() { return ''; }; } +class RejectWhenStaticPrecedesOverrideModifier extends Base { static override toStringStatic() { return ''; }; } +class AcceptWhenOverrideFollowsAccessModifier extends Base { public override toStringPublic() { return ''; } } +class RejectWhenReadonlyPrecedesOverrideModifier extends Base { readonly override id: string; } + +// Modifiers should never be repeated +class RejectWhenOverrideIsRepeated extends Base { + public override override toStringPublic() { return ''; } +} + +// You cannot override a private method +class RejectWhenOverridePrivateMethod extends Base { + private override toStringPrivate() { return ''; } + override private toStringPrivate2() { return ''; } +} + +// Override and abstract on methods are orthogonal, should never be used together +abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { + abstract override toStringAbstract(): string; + override abstract toStringAbstract2(): string; +} + +// Acceptable to provide an override implementation in an abstract class however +abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { + override toStringAbstract(): string { return 'implemented in abstract class'; } +} + +// Override checks are allowed on static methods +class AcceptWhenOverrideStaticMethod extends Base { + override static toStringStatic() { return 'static'; } +} + +// Compiler already checks for access modifier narrowing, +// override does not alter these semantics. +class RejectWhenOverrideChangesAccessModifier extends Base { + protected override static toStringStatic() { return 'member is now protected'; } +} + +// Compiler should be able to traverse multiple levels of inheritance +// to assess for overriden members (already does this). +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + override getMeaningOfLife(): number { return 12; } +} + +// Override cannot be used with optional property. +class RejectWhenOverrideOptionalProperty extends Base { + public override wasDisposed?: boolean; +} + +// If one accessor is marked override, they both should be. +class RejectWhenAccessorNotBothOverride extends Base { + override get name() { return ''; } + /* */ set name(n: string) {} +} + +// Compiler should detect when override member is not inherited or augmented +class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + public override iDontExist() { return ''; } +} + +// Compiler already detects overriden assignability mismatches, +// override keyword does not change these semantics +class RejectWhenOverrideHasMismatchedType extends Base { + override getMeaningOfLife(): string { return 'the meaning of life is a number, not a string'; } +} + +// Override is not be used on parameters +class RejectWhenOverrideIsOnAParameter { + public sayHello(override name: string) { return 'hi'; } +} + +// Override is not used on class... +override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } +override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } + +//... or interface declarations +interface RejectWhenOverrideInAnInterface { + override sayHello(name: string); +} + +/* @mhegazy: is this an appropriate test for consecutive declarations? */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + override hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } + + public getMeaningOfLife(): number { + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { + return super.propertyIsEnumerable(prop); + } +} + + +//// [overrideKeywordEs5.js] +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var AbstractBase = (function () { + function AbstractBase() { + } + Object.defineProperty(AbstractBase.prototype, "name", { + get: function () { return this.name_; }, + set: function (name) { this.name_ = name; }, + enumerable: true, + configurable: true + }); + AbstractBase.toStringStatic = function () { return 'static'; }; + AbstractBase.prototype.toStringPublic = function () { return 'public'; }; + ; + AbstractBase.prototype.toStringProtected = function () { return 'protected'; }; + AbstractBase.prototype.toStringPrivate = function () { return 'private'; }; + AbstractBase.prototype.toStringPrivate2 = function () { return 'private2'; }; + AbstractBase.prototype.getMeaningOfLife = function () { return 42; }; + return AbstractBase; +}()); +var Base = (function (_super) { + __extends(Base, _super); + function Base() { + return _super !== null && _super.apply(this, arguments) || this; + } + Base.prototype.toStringAbstract = function () { return 'implemented'; }; + Base.prototype.toStringAbstract2 = function () { return 'implemented2'; }; + return Base; +}(AbstractBase)); +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +var RejectWhenOverridePrecedesPublicModifier = (function (_super) { + __extends(RejectWhenOverridePrecedesPublicModifier, _super); + function RejectWhenOverridePrecedesPublicModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverridePrecedesPublicModifier.prototype.toStringPublic = function () { return ''; }; + ; + return RejectWhenOverridePrecedesPublicModifier; +}(Base)); +var RejectWhenOverridePrecedesProtectedModifier = (function (_super) { + __extends(RejectWhenOverridePrecedesProtectedModifier, _super); + function RejectWhenOverridePrecedesProtectedModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverridePrecedesProtectedModifier.prototype.toStringProtected = function () { return ''; }; + ; + return RejectWhenOverridePrecedesProtectedModifier; +}(Base)); +var RejectWhenStaticPrecedesOverrideModifier = (function (_super) { + __extends(RejectWhenStaticPrecedesOverrideModifier, _super); + function RejectWhenStaticPrecedesOverrideModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenStaticPrecedesOverrideModifier.toStringStatic = function () { return ''; }; + ; + return RejectWhenStaticPrecedesOverrideModifier; +}(Base)); +var AcceptWhenOverrideFollowsAccessModifier = (function (_super) { + __extends(AcceptWhenOverrideFollowsAccessModifier, _super); + function AcceptWhenOverrideFollowsAccessModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverrideFollowsAccessModifier.prototype.toStringPublic = function () { return ''; }; + return AcceptWhenOverrideFollowsAccessModifier; +}(Base)); +var RejectWhenReadonlyPrecedesOverrideModifier = (function (_super) { + __extends(RejectWhenReadonlyPrecedesOverrideModifier, _super); + function RejectWhenReadonlyPrecedesOverrideModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + return RejectWhenReadonlyPrecedesOverrideModifier; +}(Base)); +// Modifiers should never be repeated +var RejectWhenOverrideIsRepeated = (function (_super) { + __extends(RejectWhenOverrideIsRepeated, _super); + function RejectWhenOverrideIsRepeated() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideIsRepeated.prototype.toStringPublic = function () { return ''; }; + return RejectWhenOverrideIsRepeated; +}(Base)); +// You cannot override a private method +var RejectWhenOverridePrivateMethod = (function (_super) { + __extends(RejectWhenOverridePrivateMethod, _super); + function RejectWhenOverridePrivateMethod() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverridePrivateMethod.prototype.toStringPrivate = function () { return ''; }; + RejectWhenOverridePrivateMethod.prototype.toStringPrivate2 = function () { return ''; }; + return RejectWhenOverridePrivateMethod; +}(Base)); +// Override and abstract on methods are orthogonal, should never be used together +var RejectWhenOverrideAbstractMethod = (function (_super) { + __extends(RejectWhenOverrideAbstractMethod, _super); + function RejectWhenOverrideAbstractMethod() { + return _super !== null && _super.apply(this, arguments) || this; + } + return RejectWhenOverrideAbstractMethod; +}(AbstractBase)); +// Acceptable to provide an override implementation in an abstract class however +var AcceptWhenOverrideInAbstractClass = (function (_super) { + __extends(AcceptWhenOverrideInAbstractClass, _super); + function AcceptWhenOverrideInAbstractClass() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverrideInAbstractClass.prototype.toStringAbstract = function () { return 'implemented in abstract class'; }; + return AcceptWhenOverrideInAbstractClass; +}(AbstractBase)); +// Override checks are allowed on static methods +var AcceptWhenOverrideStaticMethod = (function (_super) { + __extends(AcceptWhenOverrideStaticMethod, _super); + function AcceptWhenOverrideStaticMethod() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverrideStaticMethod.toStringStatic = function () { return 'static'; }; + return AcceptWhenOverrideStaticMethod; +}(Base)); +// Compiler already checks for access modifier narrowing, +// override does not alter these semantics. +var RejectWhenOverrideChangesAccessModifier = (function (_super) { + __extends(RejectWhenOverrideChangesAccessModifier, _super); + function RejectWhenOverrideChangesAccessModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideChangesAccessModifier.toStringStatic = function () { return 'member is now protected'; }; + return RejectWhenOverrideChangesAccessModifier; +}(Base)); +// Compiler should be able to traverse multiple levels of inheritance +// to assess for overriden members (already does this). +var AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass = (function (_super) { + __extends(AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass, _super); + function AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass.prototype.getMeaningOfLife = function () { return 12; }; + return AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass; +}(Base)); +// Override cannot be used with optional property. +var RejectWhenOverrideOptionalProperty = (function (_super) { + __extends(RejectWhenOverrideOptionalProperty, _super); + function RejectWhenOverrideOptionalProperty() { + return _super !== null && _super.apply(this, arguments) || this; + } + return RejectWhenOverrideOptionalProperty; +}(Base)); +// If one accessor is marked override, they both should be. +var RejectWhenAccessorNotBothOverride = (function (_super) { + __extends(RejectWhenAccessorNotBothOverride, _super); + function RejectWhenAccessorNotBothOverride() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(RejectWhenAccessorNotBothOverride.prototype, "name", { + get: function () { return ''; }, + /* */ set: function (n) { }, + enumerable: true, + configurable: true + }); + return RejectWhenAccessorNotBothOverride; +}(Base)); +// Compiler should detect when override member is not inherited or augmented +var RejectWhenOverrideMarkedOnNonInheritedMember = (function (_super) { + __extends(RejectWhenOverrideMarkedOnNonInheritedMember, _super); + function RejectWhenOverrideMarkedOnNonInheritedMember() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideMarkedOnNonInheritedMember.prototype.iDontExist = function () { return ''; }; + return RejectWhenOverrideMarkedOnNonInheritedMember; +}(Base)); +// Compiler already detects overriden assignability mismatches, +// override keyword does not change these semantics +var RejectWhenOverrideHasMismatchedType = (function (_super) { + __extends(RejectWhenOverrideHasMismatchedType, _super); + function RejectWhenOverrideHasMismatchedType() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideHasMismatchedType.prototype.getMeaningOfLife = function () { return 'the meaning of life is a number, not a string'; }; + return RejectWhenOverrideHasMismatchedType; +}(Base)); +// Override is not be used on parameters +var RejectWhenOverrideIsOnAParameter = (function () { + function RejectWhenOverrideIsOnAParameter() { + } + RejectWhenOverrideIsOnAParameter.prototype.sayHello = function (name) { return 'hi'; }; + return RejectWhenOverrideIsOnAParameter; +}()); +// Override is not used on class... +var RejectWhenOverrideIsOnClassDeclaration = (function () { + function RejectWhenOverrideIsOnClassDeclaration() { + } + RejectWhenOverrideIsOnClassDeclaration.prototype.sayHello = function (name) { return ''; }; + return RejectWhenOverrideIsOnClassDeclaration; +}()); +/* @mhegazy: is this an appropriate test for consecutive declarations? */ +var RejectWhenOverrideDeclarationsAreNotConsecutive = (function (_super) { + __extends(RejectWhenOverrideDeclarationsAreNotConsecutive, _super); + function RejectWhenOverrideDeclarationsAreNotConsecutive() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.hasOwnProperty = function (prop) { + return _super.prototype.hasOwnProperty.call(this, prop); + }; + RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.getMeaningOfLife = function () { + return 42; + }; + RejectWhenOverrideDeclarationsAreNotConsecutive.prototype.propertyIsEnumerable = function (prop) { + return _super.prototype.propertyIsEnumerable.call(this, prop); + }; + return RejectWhenOverrideDeclarationsAreNotConsecutive; +}(Base)); + + +//// [overrideKeywordEs5.d.ts] +declare abstract class AbstractBase { + readonly id: string; + wasDisposed?: boolean; + private name_; + name: string; + static toStringStatic(): string; + toStringPublic(): string; + protected toStringProtected(): string; + private toStringPrivate(); + private toStringPrivate2(); + abstract toStringAbstract(): string; + abstract toStringAbstract2(): string; + getMeaningOfLife(): number; +} +declare class Base extends AbstractBase { + override toStringAbstract(): string; + override toStringAbstract2(): string; +} +declare class RejectWhenOverridePrecedesPublicModifier extends Base { + override toStringPublic(): string; +} +declare class RejectWhenOverridePrecedesProtectedModifier extends Base { + protected override toStringProtected(): string; +} +declare class RejectWhenStaticPrecedesOverrideModifier extends Base { + static override toStringStatic(): string; +} +declare class AcceptWhenOverrideFollowsAccessModifier extends Base { + override toStringPublic(): string; +} +declare class RejectWhenReadonlyPrecedesOverrideModifier extends Base { + override readonly id: string; +} +declare class RejectWhenOverrideIsRepeated extends Base { + override toStringPublic(): string; +} +declare class RejectWhenOverridePrivateMethod extends Base { + private override toStringPrivate(); + private override toStringPrivate2(); +} +declare abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { + override abstract toStringAbstract(): string; + override abstract toStringAbstract2(): string; +} +declare abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { + override toStringAbstract(): string; +} +declare class AcceptWhenOverrideStaticMethod extends Base { + static override toStringStatic(): string; +} +declare class RejectWhenOverrideChangesAccessModifier extends Base { + protected static override toStringStatic(): string; +} +declare class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + override getMeaningOfLife(): number; +} +declare class RejectWhenOverrideOptionalProperty extends Base { + override wasDisposed?: boolean; +} +declare class RejectWhenAccessorNotBothOverride extends Base { + override name: string; +} +declare class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + override iDontExist(): string; +} +declare class RejectWhenOverrideHasMismatchedType extends Base { + override getMeaningOfLife(): string; +} +declare class RejectWhenOverrideIsOnAParameter { + sayHello(name: string): string; +} +declare class RejectWhenOverrideIsOnClassDeclaration { + sayHello(name: string): string; +} +interface RejectWhenOverrideIsOnInterfaceDeclaration { + sayHello(name: string): any; +} +interface RejectWhenOverrideInAnInterface { + sayHello(name: string): any; +} +declare class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + override hasOwnProperty(prop: string): boolean; + getMeaningOfLife(): number; + override propertyIsEnumerable(prop: string): boolean; +} diff --git a/tests/baselines/reference/overrideKeywordEs6.errors.txt b/tests/baselines/reference/overrideKeywordEs6.errors.txt new file mode 100644 index 0000000000000..2596b39a7d978 --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs6.errors.txt @@ -0,0 +1,19 @@ +tests/cases/compiler/overrideKeywordEs6.ts(11,68): error TS1029: 'override' modifier must precede 'async' modifier. + + +==== tests/cases/compiler/overrideKeywordEs6.ts (1 errors) ==== + + class Base { + async getMeaningOfLife1(): Promise { return Promise.resolve(42); } + async getMeaningOfLife2(): Promise { return Promise.reject(42); } + } + + // The expected order of modifiers: + // + // [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier + // + class RejectWhenAsyncPrecedesOverrideModifier extends Base { async override getMeaningOfLife1(): Promise { return Promise.reject(42); }; } + ~~~~~~~~ +!!! error TS1029: 'override' modifier must precede 'async' modifier. + class AcceptWhenOverridePrecedesAsyncModifier extends Base { override async getMeaningOfLife2(): Promise { return Promise.resolve(42); }; } + \ No newline at end of file diff --git a/tests/baselines/reference/overrideKeywordEs6.js b/tests/baselines/reference/overrideKeywordEs6.js new file mode 100644 index 0000000000000..150728dc0c74f --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs6.js @@ -0,0 +1,61 @@ +//// [overrideKeywordEs6.ts] + +class Base { + async getMeaningOfLife1(): Promise { return Promise.resolve(42); } + async getMeaningOfLife2(): Promise { return Promise.reject(42); } +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenAsyncPrecedesOverrideModifier extends Base { async override getMeaningOfLife1(): Promise { return Promise.reject(42); }; } +class AcceptWhenOverridePrecedesAsyncModifier extends Base { override async getMeaningOfLife2(): Promise { return Promise.resolve(42); }; } + + +//// [overrideKeywordEs6.js] +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +class Base { + getMeaningOfLife1() { + return __awaiter(this, void 0, void 0, function* () { return Promise.resolve(42); }); + } + getMeaningOfLife2() { + return __awaiter(this, void 0, void 0, function* () { return Promise.reject(42); }); + } +} +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenAsyncPrecedesOverrideModifier extends Base { + getMeaningOfLife1() { + return __awaiter(this, void 0, void 0, function* () { return Promise.reject(42); }); + } + ; +} +class AcceptWhenOverridePrecedesAsyncModifier extends Base { + getMeaningOfLife2() { + return __awaiter(this, void 0, void 0, function* () { return Promise.resolve(42); }); + } + ; +} + + +//// [overrideKeywordEs6.d.ts] +declare class Base { + getMeaningOfLife1(): Promise; + getMeaningOfLife2(): Promise; +} +declare class RejectWhenAsyncPrecedesOverrideModifier extends Base { + override getMeaningOfLife1(): Promise; +} +declare class AcceptWhenOverridePrecedesAsyncModifier extends Base { + override getMeaningOfLife2(): Promise; +} diff --git a/tests/cases/compiler/noImplicitOverride.ts b/tests/cases/compiler/noImplicitOverride.ts index 6036d7d8d024e..ab1aa1579b79f 100644 --- a/tests/cases/compiler/noImplicitOverride.ts +++ b/tests/cases/compiler/noImplicitOverride.ts @@ -5,6 +5,7 @@ class Base { get name(): string { return 'Base'; } + getMeaningOfLife(): number { return 42; } public userId: number = 1; } @@ -15,7 +16,7 @@ class RejectWhenOverrideMissingOnInheritedMethod extends Object { } } -class RejectWhenOverrideMissingOnMethodThatMasksObjectTypeMember { +class RejectWhenOverrideMissingOnAugmentedProperty { toString(): string { return 'foo'; }; hasOwnProperty(prop: string): boolean { return false; diff --git a/tests/cases/compiler/overrideKeyword.ts b/tests/cases/compiler/overrideKeyword.ts deleted file mode 100644 index b7b0cf43baa74..0000000000000 --- a/tests/cases/compiler/overrideKeyword.ts +++ /dev/null @@ -1,89 +0,0 @@ -// @noImplicitOverride: true -// @target: es5 - -abstract class AbstractBase { - static toStringStatic(): string { return 'static member'; } - public toString(): string { return 'instance member'; }; - abstract toStringAbstract(): string; - private toStringPrivate(): string { return 'private member'; } - getMeaningOfLife(): number { return 42; } - public wasDisposed?: boolean; -} - -class Base extends AbstractBase { - private name_: string; - - toStringAbstract(): string { return 'implementation of abstract member'; }; - - get name() { - return this.name_; - } - - set name(name: string) { - this.name_ = name; - } - - // override cannot be used with optional property. - public override wasDisposed?: boolean; -} - -abstract class RejectWhenAttemptToOverrideAbstractMethod extends AbstractBase { - abstract override toStringAbstract(): string; -} - -class RejectWhenAttemptToOverrideStaticMethod extends Base { - override static toStringStatic() { return ''; }; -} - -class RejectWhenAttemptToOverridePrivateMethod extends Base { - private override toStringPrivate() { return ''; }; -} - -class RejectWhenOverrideIsRepeated extends Base { - public override override toString() { return ''; }; -} - -class RejectWhenOverridePrecedesAccessModifier extends Base { - override public toString() { return ''; }; -} - -class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { - public override iDontExist() { return ''; }; -} - -class RejectWhenOverrideHasMismatchedType extends Base { - override getMeaningOfLife(): string { return 'forty-two'; }; -} - -class RejectWhenAccessorNotBothOverride extends Base { - override get name() { - return 'hardcoded value'; - } - set name(n: string) { - } -} - -/* @mhegazy: is this an appropriate test for consecutive declarations? */ -class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { - - override hasOwnProperty(prop: string): boolean { - return super.hasOwnProperty(prop); - } - - public getMeaningOfLife(): number { - return 42; - } - - override propertyIsEnumerable(prop: string): boolean { - return super.propertyIsEnumerable(prop); - } - -} - -class AcceptWhenOverrideFollowsAccessModifier extends Base { - public override toString() { return ''; }; -} - -class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { - public override getMeaningOfLife(): number { return 12; }; -} diff --git a/tests/cases/compiler/overrideKeywordEs5.ts b/tests/cases/compiler/overrideKeywordEs5.ts new file mode 100644 index 0000000000000..c72dc83c55970 --- /dev/null +++ b/tests/cases/compiler/overrideKeywordEs5.ts @@ -0,0 +1,126 @@ +// @declaration: true +// @noImplicitOverride: false +// @target: es5 + +abstract class AbstractBase { + readonly id: string; + public wasDisposed?: boolean; + private name_: string; + get name() { return this.name_; } + set name(name: string) { this.name_ = name; } + + static toStringStatic(): string { return 'static'; } + public toStringPublic(): string { return 'public'; }; + protected toStringProtected(): string { return 'protected'; } + private toStringPrivate(): string { return 'private'; } + private toStringPrivate2(): string { return 'private2'; } + abstract toStringAbstract(): string; + abstract toStringAbstract2(): string; + + getMeaningOfLife(): number { return 42; } +} + +class Base extends AbstractBase { + override toStringAbstract(): string { return 'implemented'; } + override toStringAbstract2(): string { return 'implemented2'; } +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenOverridePrecedesPublicModifier extends Base { override public toStringPublic() { return ''; }; } +class RejectWhenOverridePrecedesProtectedModifier extends Base { override protected toStringProtected() { return ''; }; } +class RejectWhenStaticPrecedesOverrideModifier extends Base { static override toStringStatic() { return ''; }; } +class AcceptWhenOverrideFollowsAccessModifier extends Base { public override toStringPublic() { return ''; } } +class RejectWhenReadonlyPrecedesOverrideModifier extends Base { readonly override id: string; } + +// Modifiers should never be repeated +class RejectWhenOverrideIsRepeated extends Base { + public override override toStringPublic() { return ''; } +} + +// You cannot override a private method +class RejectWhenOverridePrivateMethod extends Base { + private override toStringPrivate() { return ''; } + override private toStringPrivate2() { return ''; } +} + +// Override and abstract on methods are orthogonal, should never be used together +abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { + abstract override toStringAbstract(): string; + override abstract toStringAbstract2(): string; +} + +// Acceptable to provide an override implementation in an abstract class however +abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { + override toStringAbstract(): string { return 'implemented in abstract class'; } +} + +// Override checks are allowed on static methods +class AcceptWhenOverrideStaticMethod extends Base { + override static toStringStatic() { return 'static'; } +} + +// Compiler already checks for access modifier narrowing, +// override does not alter these semantics. +class RejectWhenOverrideChangesAccessModifier extends Base { + protected override static toStringStatic() { return 'member is now protected'; } +} + +// Compiler should be able to traverse multiple levels of inheritance +// to assess for overriden members (already does this). +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { + override getMeaningOfLife(): number { return 12; } +} + +// Override cannot be used with optional property. +class RejectWhenOverrideOptionalProperty extends Base { + public override wasDisposed?: boolean; +} + +// If one accessor is marked override, they both should be. +class RejectWhenAccessorNotBothOverride extends Base { + override get name() { return ''; } + /* */ set name(n: string) {} +} + +// Compiler should detect when override member is not inherited or augmented +class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { + public override iDontExist() { return ''; } +} + +// Compiler already detects overriden assignability mismatches, +// override keyword does not change these semantics +class RejectWhenOverrideHasMismatchedType extends Base { + override getMeaningOfLife(): string { return 'the meaning of life is a number, not a string'; } +} + +// Override is not be used on parameters +class RejectWhenOverrideIsOnAParameter { + public sayHello(override name: string) { return 'hi'; } +} + +// Override is not used on class... +override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } +override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } + +//... or interface declarations +interface RejectWhenOverrideInAnInterface { + override sayHello(name: string); +} + +/* @mhegazy: is this an appropriate test for consecutive declarations? */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { + override hasOwnProperty(prop: string): boolean { + return super.hasOwnProperty(prop); + } + + public getMeaningOfLife(): number { + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { + return super.propertyIsEnumerable(prop); + } +} diff --git a/tests/cases/compiler/overrideKeywordEs6.ts b/tests/cases/compiler/overrideKeywordEs6.ts new file mode 100644 index 0000000000000..a6f3d6a530034 --- /dev/null +++ b/tests/cases/compiler/overrideKeywordEs6.ts @@ -0,0 +1,15 @@ +// @declaration: true +// @noImplicitOverride: false +// @target: es6 + +class Base { + async getMeaningOfLife1(): Promise { return Promise.resolve(42); } + async getMeaningOfLife2(): Promise { return Promise.reject(42); } +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenAsyncPrecedesOverrideModifier extends Base { async override getMeaningOfLife1(): Promise { return Promise.reject(42); }; } +class AcceptWhenOverridePrecedesAsyncModifier extends Base { override async getMeaningOfLife2(): Promise { return Promise.resolve(42); }; } From a1cdd8c43502569dbb2687cb918aab1112176fb1 Mon Sep 17 00:00:00 2001 From: Paul Johnston Date: Thu, 19 Jan 2017 20:35:57 -0700 Subject: [PATCH 4/9] Include transpile reference test --- .../reference/transpile/Supports setting noImplicitOverride.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/baselines/reference/transpile/Supports setting noImplicitOverride.js diff --git a/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js b/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js new file mode 100644 index 0000000000000..8d91090453b8a --- /dev/null +++ b/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js @@ -0,0 +1,3 @@ +"use strict"; +x; +//# sourceMappingURL=input.js.map \ No newline at end of file From 36264039fb33d05f3a9434c46b05135f14e66e12 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Fri, 1 Dec 2017 20:29:58 -0700 Subject: [PATCH 5/9] Resolve compiler errors following merge --- src/compiler/checker.ts | 45 +++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3f2c3f0d6044d..1ed033728d7d2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2994,7 +2994,11 @@ namespace ts { function cloneBindingName(node: BindingName): BindingName { return elideInitializerAndSetEmitFlags(node); function elideInitializerAndSetEmitFlags(node: Node): Node { - const visited = visitEachChild(node, elideInitializerAndSetEmitFlags, nullTransformationContext, /*nodesVisitor*/ undefined, elideInitializerAndSetEmitFlags); + const visited = visitEachChild(node, + elideInitializerAndSetEmitFlags, + nullTransformationContext, + /*nodesVisitor*/ undefined, + elideInitializerAndSetEmitFlags); const clone = nodeIsSynthesized(visited) ? visited : getSynthesizedClone(visited); if (clone.kind === SyntaxKind.BindingElement) { (clone).initializer = undefined; @@ -19652,7 +19656,7 @@ namespace ts { function checkOverrideDeclaration(node: MethodDeclaration | PropertyDeclaration | AccessorDeclaration) { if (node.questionToken) { - error(node, Diagnostics.override_modifier_cannot_be_used_with_an_optional_property_declaration); + error(node, Diagnostics.Override_modifier_cannot_be_used_with_an_optional_property_declaration); } } @@ -20025,7 +20029,7 @@ namespace ts { error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract); } else if (deviation & ModifierFlags.Override) { - error(o.name, Diagnostics.Overload_signatures_must_all_be_override_or_non_override); + error(getNameOfDeclaration(o), Diagnostics.Overload_signatures_must_all_be_override_or_non_override); } }); } @@ -22564,9 +22568,9 @@ namespace ts { } } else { - const properties = createMap(); + const properties = createUnderscoreEscapedMap(); for (const prop of getPropertiesOfObjectType(type)) { - properties[prop.name] = prop; + properties.set(prop.escapedName, prop); } checkAugmentedPropertyMemberOverrides(type, properties); } @@ -22622,25 +22626,26 @@ namespace ts { return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined); } - function checkAugmentedPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map): void { + function checkAugmentedPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: UnderscoreEscapedMap): void { // If the class does not explicitly declare 'extends Object', // declarations that mask 'Object' members ('toString()', 'hasOwnProperty()', etc...) // are considered here. // check is disabled in ambient contexts - if (isInAmbientContext(type.symbol.valueDeclaration)) { + if (type.symbol.valueDeclaration.flags & NodeFlags.Ambient) { return; } - const objectType = getSymbol(globals, "Object", SymbolFlags.Type); + // Use escapeLeadingUnderscores here to get a '__String' instance (rather than 'string') + const objectType = getSymbol(globals, escapeLeadingUnderscores("Object"), SymbolFlags.Type); if (!objectType) { return; } - for (const name in propertiesToCheck) { - const derived = getTargetSymbol(propertiesToCheck[name]); + propertiesToCheck.forEach((symbol: Symbol, name: __String) => { + const derived = getTargetSymbol(symbol); const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived); - const found = objectType.members[name]; + const found = objectType.members.get(name); if (found) { if (compilerOptions.noImplicitOverride) { const foundSymbol = getTargetSymbol(found); @@ -22658,21 +22663,21 @@ namespace ts { typeToString(getTypeOfSymbol(foundSymbol)) ); } - diagnostics.add(createDiagnosticForNodeFromMessageChain(derived.valueDeclaration.name, errorInfo)); + diagnostics.add(createDiagnosticForNodeFromMessageChain(getDeclarationName(derived.valueDeclaration), errorInfo)); } } // No matching property found on the object type. It // is an error for the derived property to falsely // claim 'override'. else if (derivedDeclarationFlags & ModifierFlags.Override) { - error(derived.valueDeclaration.name, + error(getDeclarationName(derived.valueDeclaration), Diagnostics.Class_member_0_was_marked_override_but_no_matching_declaration_was_found_in_any_supertype_of_1, symbolToString(derived), typeToString(type)); } - } + }); } - + function getClassOrInterfaceDeclarationsOfSymbol(symbol: Symbol) { return filter(symbol.declarations, (d: Declaration): d is ClassDeclaration | InterfaceDeclaration => d.kind === SyntaxKind.ClassDeclaration || d.kind === SyntaxKind.InterfaceDeclaration); @@ -22698,18 +22703,18 @@ namespace ts { // NOTE: assignability is checked in checkClassDeclaration // Track which symbols in the derived class have not been seen. - const onlyInDerived = createMap(); + const onlyInDerived = createUnderscoreEscapedMap(); // TODO(pcj): Should this be getPropertiesOfType or getPropertiesOfObjectType? for (const prop of getPropertiesOfType(type)) { - onlyInDerived[prop.name] = prop; + onlyInDerived.set(prop.escapedName, prop); } - const ambient = isInAmbientContext(type.symbol.valueDeclaration); + const ambient = type.symbol.valueDeclaration.flags & NodeFlags.Ambient; const baseProperties = getPropertiesOfType(baseType); for (const baseProperty of baseProperties) { const base = getTargetSymbol(baseProperty); - delete onlyInDerived[base.name]; + onlyInDerived.delete(base.escapedName); if (base.flags & SymbolFlags.Prototype) { continue; @@ -22761,7 +22766,7 @@ namespace ts { && !ambient && !(derivedDeclarationFlags & ModifierFlags.Abstract) && !(derivedDeclarationFlags & ModifierFlags.Override)) { - error(derived.valueDeclaration.name, + error(getDeclarationName(derived.valueDeclaration), Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1, symbolToString(derived), typeToString(baseType)); From c791e7cf75050f58a92a97b846f9215c37717186 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Fri, 1 Dec 2017 21:20:26 -0700 Subject: [PATCH 6/9] Restore master spec.md; Stop nodejs mem crash --- doc/spec.md | 3080 +++++++++++++++++++-------------------- src/compiler/checker.ts | 6 +- 2 files changed, 1545 insertions(+), 1541 deletions(-) diff --git a/doc/spec.md b/doc/spec.md index e9f84933c2e15..fa69d32105663 100644 --- a/doc/spec.md +++ b/doc/spec.md @@ -258,8 +258,8 @@ var i = 0; TypeScript will infer from the following function definition that the function f has return type string. ```TypeScript -function f() { - return "hello"; +function f() { + return "hello"; } ``` @@ -270,19 +270,19 @@ To benefit from this inference, a programmer can use the TypeScript language ser In this example, the programmer benefits from type inference without providing type annotations. Some beneficial tools, however, do require the programmer to provide type annotations. In TypeScript, we can express a parameter requirement as in the following code fragment. ```TypeScript -function f(s: string) { - return s; +function f(s: string) { + return s; } -f({}); // Error +f({}); // Error f("hello"); // Ok ``` This optional type annotation on the parameter 's' lets the TypeScript type checker know that the programmer expects parameter 's' to be of type 'string'. Within the body of function 'f', tools can assume 's' is of type 'string' and provide operator type checking and member completion consistent with this assumption. Tools can also signal an error on the first call to 'f', because 'f' expects a string, not an object, as its parameter. For the function 'f', the TypeScript compiler will emit the following JavaScript code: ```TypeScript -function f(s) { - return s; +function f(s) { + return s; } ``` @@ -293,7 +293,7 @@ In the JavaScript output, all type annotations have been erased. In general, Typ An ambient declaration introduces a variable into a TypeScript scope, but has zero impact on the emitted JavaScript program. Programmers can use ambient declarations to tell the TypeScript compiler that some other component will supply a variable. For example, by default the TypeScript compiler will print an error for uses of undefined variables. To add some of the common variables defined by browsers, a TypeScript programmer can use ambient declarations. The following example declares the 'document' object supplied by browsers. Because the declaration does not specify a type, the type 'any' is inferred. The type 'any' means that a tool can assume nothing about the shape or behavior of the document object. Some of the examples below will illustrate how programmers can use types to further characterize the expected behavior of an object. ```TypeScript -declare var document; +declare var document; document.title = "Hello"; // Ok because document has been declared ``` @@ -314,16 +314,16 @@ Function expressions are a powerful feature of JavaScript. They enable function TypeScript function types make it possible for programmers to express the expected *signature* of a function. A function signature is a sequence of parameter types plus a return type. The following example uses function types to express the callback signature requirements of an asynchronous voting mechanism. ```TypeScript -function vote(candidate: string, callback: (result: string) => any) { - // ... +function vote(candidate: string, callback: (result: string) => any) { + // ... } -vote("BigPig", - function(result: string) { - if (result === "BigPig") { - // ... - } - } +vote("BigPig", + function(result: string) { + if (result === "BigPig") { + // ... + } + } ); ``` @@ -342,25 +342,25 @@ Section [3.9.2](#3.9.2) provides additional information about function types. TypeScript programmers use *object types* to declare their expectations of object behavior. The following code uses an *object type literal* to specify the return type of the 'MakePoint' function. ```TypeScript -var MakePoint: () => { - x: number; y: number; +var MakePoint: () => { + x: number; y: number; }; ``` Programmers can give names to object types; we call named object types *interfaces*. For example, in the following code, an interface declares one required field (name) and one optional field (favoriteColor). ```TypeScript -interface Friend { - name: string; - favoriteColor?: string; +interface Friend { + name: string; + favoriteColor?: string; } -function add(friend: Friend) { - var name = friend.name; +function add(friend: Friend) { + var name = friend.name; } -add({ name: "Fred" }); // Ok -add({ favoriteColor: "blue" }); // Error, name required +add({ name: "Fred" }); // Ok +add({ favoriteColor: "blue" }); // Error, name required add({ name: "Jill", favoriteColor: "green" }); // Ok ``` @@ -369,27 +369,27 @@ TypeScript object types model the diversity of behaviors that a JavaScript objec The following code fragment captures a small subset of jQuery behavior, just enough to use jQuery in a simple way. ```TypeScript -interface JQuery { - text(content: string); -} - -interface JQueryStatic { - get(url: string, callback: (data: string) => any); - (query: string): JQuery; +interface JQuery { + text(content: string); +} + +interface JQueryStatic { + get(url: string, callback: (data: string) => any); + (query: string): JQuery; } declare var $: JQueryStatic; -$.get("http://mysite.org/divContent", - function (data: string) { - $("div").text(data); - } +$.get("http://mysite.org/divContent", + function (data: string) { + $("div").text(data); + } ); ``` The 'JQueryStatic' interface references another interface: 'JQuery'. This interface represents a collection of one or more DOM elements. The jQuery library can perform many operations on such a collection, but in this example the jQuery client only needs to know that it can set the text content of each jQuery element in a collection by passing a string to the 'text' method. The 'JQueryStatic' interface also contains a method, 'get', that performs an Ajax get operation on the provided URL and arranges to invoke the provided callback upon receipt of a response. -Finally, the 'JQueryStatic' interface contains a bare function signature +Finally, the 'JQueryStatic' interface contains a bare function signature ```TypeScript (query: string): JQuery; @@ -398,8 +398,8 @@ Finally, the 'JQueryStatic' interface contains a bare function signature The bare signature indicates that instances of the interface are callable. This example illustrates that TypeScript function types are just special cases of TypeScript object types. Specifically, function types are object types that contain one or more call signatures. For this reason we can write any function type as an object type literal. The following example uses both forms to describe the same type. ```TypeScript -var f: { (): string; }; -var sameType: () => string = f; // Ok +var f: { (): string; }; +var sameType: () => string = f; // Ok var nope: () => number = sameType; // Error: type mismatch ``` @@ -422,22 +422,22 @@ Section [3.3](#3.3) provides additional information about object types. Object types are compared *structurally*. For example, in the code fragment below, class 'CPoint' matches interface 'Point' because 'CPoint' has all of the required members of 'Point'. A class may optionally declare that it implements an interface, so that the compiler will check the declaration for structural compatibility. The example also illustrates that an object type can match the type inferred from an object literal, as long as the object literal supplies all of the required members. ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } -function getX(p: Point) { - return p.x; +function getX(p: Point) { + return p.x; } -class CPoint { - x: number; - y: number; - constructor(x: number, y: number) { - this.x = x; - this.y = y; - } +class CPoint { + x: number; + y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } } getX(new CPoint(0, 0)); // Ok, fields match @@ -454,8 +454,8 @@ See section [3.11](#3.11) for more information about type comparisons. Ordinarily, TypeScript type inference proceeds "bottom-up": from the leaves of an expression tree to its root. In the following example, TypeScript infers 'number' as the return type of the function 'mul' by flowing type information bottom up in the return expression. ```TypeScript -function mul(a: number, b: number) { - return a * b; +function mul(a: number, b: number) { + return a * b; } ``` @@ -464,10 +464,10 @@ For variables and parameters without a type annotation or a default value, TypeS However, in some limited contexts, inference proceeds "top-down" from the context of an expression. Where this happens, it is called contextual typing. Contextual typing helps tools provide excellent information when a programmer is using a type but may not know all of the details of the type. For example, in the jQuery example, above, the programmer supplies a function expression as the second parameter to the 'get' method. During typing of that expression, tools can assume that the type of the function expression is as given in the 'get' signature and can provide a template that includes parameter names and types. ```TypeScript -$.get("http://mysite.org/divContent", - function (data) { - $("div").text(data); // TypeScript infers data is a string - } +$.get("http://mysite.org/divContent", + function (data) { + $("div").text(data); // TypeScript infers data is a string + } ); ``` @@ -482,36 +482,36 @@ JavaScript practice has two very common design patterns: the module pattern and This section and the namespace section below will show how TypeScript emits consistent, idiomatic JavaScript when emitting ECMAScript 3 or 5 compliant code for classes and namespaces. The goal of TypeScript's translation is to emit exactly what a programmer would type when implementing a class or namespace unaided by a tool. This section will also describe how TypeScript infers a type for each class declaration. We'll start with a simple BankAccount class. ```TypeScript -class BankAccount { - balance = 0; - deposit(credit: number) { - this.balance += credit; - return this.balance; - } -} +class BankAccount { + balance = 0; + deposit(credit: number) { + this.balance += credit; + return this.balance; + } +} ``` This class generates the following JavaScript code. ```TypeScript -var BankAccount = (function () { - function BankAccount() { - this.balance = 0; - } - BankAccount.prototype.deposit = function(credit) { - this.balance += credit; - return this.balance; - }; - return BankAccount; +var BankAccount = (function () { + function BankAccount() { + this.balance = 0; + } + BankAccount.prototype.deposit = function(credit) { + this.balance += credit; + return this.balance; + }; + return BankAccount; })(); ``` This TypeScript class declaration creates a variable named 'BankAccount' whose value is the constructor function for 'BankAccount' instances. This declaration also creates an instance type of the same name. If we were to write this type as an interface it would look like the following. ```TypeScript -interface BankAccount { - balance: number; - deposit(credit: number): number; +interface BankAccount { + balance: number; + deposit(credit: number): number; } ``` @@ -526,28 +526,28 @@ The function signature is prefixed with the keyword 'new' indicating that the 'B If we want to start our bank account with an initial balance, we can add to the 'BankAccount' class a constructor declaration. ```TypeScript -class BankAccount { - balance: number; - constructor(initially: number) { - this.balance = initially; - } - deposit(credit: number) { - this.balance += credit; - return this.balance; - } +class BankAccount { + balance: number; + constructor(initially: number) { + this.balance = initially; + } + deposit(credit: number) { + this.balance += credit; + return this.balance; + } } ``` This version of the 'BankAccount' class requires us to introduce a constructor parameter and then assign it to the 'balance' field. To simplify this common case, TypeScript accepts the following shorthand syntax. ```TypeScript -class BankAccount { - constructor(public balance: number) { - } - deposit(credit: number) { - this.balance += credit; - return this.balance; - } +class BankAccount { + constructor(public balance: number) { + } + deposit(credit: number) { + this.balance += credit; + return this.balance; + } } ``` @@ -556,19 +556,19 @@ The 'public' keyword denotes that the constructor parameter is to be retained as TypeScript classes also support inheritance, as in the following example.* * ```TypeScript -class CheckingAccount extends BankAccount { - constructor(balance: number) { - super(balance); - } - writeCheck(debit: number) { - this.balance -= debit; - } +class CheckingAccount extends BankAccount { + constructor(balance: number) { + super(balance); + } + writeCheck(debit: number) { + this.balance -= debit; + } } ``` -In this example, the class 'CheckingAccount' *derives* from class 'BankAccount'. The constructor for 'CheckingAccount' calls the constructor for class 'BankAccount' using the 'super' keyword. In the emitted JavaScript code, the prototype of 'CheckingAccount' will chain to the prototype of 'BankAccount'. +In this example, the class 'CheckingAccount' *derives* from class 'BankAccount'. The constructor for 'CheckingAccount' calls the constructor for class 'BankAccount' using the 'super' keyword. In the emitted JavaScript code, the prototype of 'CheckingAccount' will chain to the prototype of 'BankAccount'. -TypeScript classes may also specify static members. Static class members become properties of the class constructor. +TypeScript classes may also specify static members. Static class members become properties of the class constructor. Section [8](#8) provides additional information about classes. @@ -577,16 +577,16 @@ Section [8](#8) provides additional information about classes. TypeScript enables programmers to summarize a set of numeric constants as an *enum type*. The example below creates an enum type to represent operators in a calculator application. ```TypeScript -const enum Operator { - ADD, - DIV, - MUL, - SUB +const enum Operator { + ADD, + DIV, + MUL, + SUB } -function compute(op: Operator, a: number, b: number) { - console.log("the operator is" + Operator[op]); - // ... +function compute(op: Operator, a: number, b: number) { + console.log("the operator is" + Operator[op]); + // ... } ``` @@ -597,28 +597,28 @@ When enums are declared with the `const` modifier, the TypeScript compiler will For example, the 'compute' function could contain a switch statement like the following. ```TypeScript -switch (op) { - case Operator.ADD: - // execute add - break; - case Operator.DIV: - // execute div - break; - // ... +switch (op) { + case Operator.ADD: + // execute add + break; + case Operator.DIV: + // execute div + break; + // ... } ``` For this switch statement, the compiler will generate the following code. ```TypeScript -switch (op) { - case 0 /* Operator.ADD */: - // execute add - break; - case 1 /* Operator.DIV */: - // execute div - break; - // ... +switch (op) { + case 0 /* Operator.ADD */: + // execute add + break; + case 1 /* Operator.DIV */: + // execute div + break; + // ... } ``` @@ -635,7 +635,7 @@ JavaScript programming interfaces often include functions whose behavior is disc The following code fragment uses this feature. Because the 'span' variable is inferred to have the type 'HTMLSpanElement', the code can reference without static error the 'isMultiline' property of 'span'. ```TypeScript -var span = document.createElement("span"); +var span = document.createElement("span"); span.isMultiLine = false; // OK: HTMLSpanElement has isMultiline property ``` @@ -652,10 +652,10 @@ Like overloading on string parameters, *generic types* make it easier for TypeSc To illustrate this, let's take a look at part of the TypeScript interface for the built-in JavaScript array type. You can find this interface in the 'lib.d.ts' file that accompanies a TypeScript distribution. ```TypeScript -interface Array { - reverse(): T[]; - sort(compareFn?: (a: T, b: T) => number): T[]; - // ... +interface Array { + reverse(): T[]; + sort(compareFn?: (a: T, b: T) => number): T[]; + // ... } ``` @@ -672,9 +672,9 @@ The map method, invoked on an array 'a' with element type 'T', will apply functi The TypeScript compiler can often infer generic method parameters, making it unnecessary for the programmer to explicitly provide them. In the following example, the compiler infers that parameter 'U' of the map method has type 'string', because the function passed to map returns a string. ```TypeScript -function numberToString(a: number[]) { - var stringArray = a.map(v => v.toString()); - return stringArray; +function numberToString(a: number[]) { + var stringArray = a.map(v => v.toString()); + return stringArray; } ``` @@ -683,27 +683,27 @@ The compiler infers in this example that the 'numberToString' function returns a In TypeScript, classes can also have type parameters. The following code declares a class that implements a linked list of items of type 'T'. This code illustrates how programmers can *constrain* type parameters to extend a specific type. In this case, the items on the list must extend the type 'NamedItem'. This enables the programmer to implement the 'log' function, which logs the name of the item. ```TypeScript -interface NamedItem { - name: string; +interface NamedItem { + name: string; } -class List { +class List { next: List = null; - constructor(public item: T) { + constructor(public item: T) { } - insertAfter(item: T) { - var temp = this.next; - this.next = new List(item); - this.next.next = temp; + insertAfter(item: T) { + var temp = this.next; + this.next = new List(item); + this.next.next = temp; } - log() { - console.log(this.item.name); + log() { + console.log(this.item.name); } - // ... + // ... } ``` @@ -713,17 +713,17 @@ Section [3.7](#3.7) provides further information about generic types. Classes and interfaces support large-scale JavaScript development by providing a mechanism for describing how to use a software component that can be separated from that component's implementation. TypeScript enforces *encapsulation* of implementation in classes at design time (by restricting use of private and protected members), but cannot enforce encapsulation at runtime because all object properties are accessible at runtime. Future versions of JavaScript may provide *private names* which would enable runtime enforcement of private and protected members. -In JavaScript, a very common way to enforce encapsulation at runtime is to use the module pattern: encapsulate private fields and methods using closure variables. The module pattern is a natural way to provide organizational structure and dynamic loading options by drawing a boundary around a software component. The module pattern can also provide the ability to introduce namespaces, avoiding use of the global namespace for most software components. +In JavaScript, a very common way to enforce encapsulation at runtime is to use the module pattern: encapsulate private fields and methods using closure variables. The module pattern is a natural way to provide organizational structure and dynamic loading options by drawing a boundary around a software component. The module pattern can also provide the ability to introduce namespaces, avoiding use of the global namespace for most software components. The following example illustrates the JavaScript module pattern. ```TypeScript -(function(exports) { - var key = generateSecretKey(); - function sendMessage(message) { - sendSecureMessage(message, key); - } - exports.sendMessage = sendMessage; +(function(exports) { + var key = generateSecretKey(); + function sendMessage(message) { + sendSecureMessage(message, key); + } + exports.sendMessage = sendMessage; })(MessageModule); ``` @@ -736,22 +736,22 @@ TypeScript namespaces provide a mechanism for succinctly expressing the module p The following example shows the definition and use of a simple namespace. ```TypeScript -namespace M { - var s = "hello"; - export function f() { - return s; - } +namespace M { + var s = "hello"; + export function f() { + return s; + } } -M.f(); +M.f(); M.s; // Error, s is not exported ``` In this example, variable 's' is a private feature of the namespace, but function 'f' is exported from the namespace and accessible to code outside of the namespace. If we were to describe the effect of namespace 'M' in terms of interfaces and variables, we would write ```TypeScript -interface M { - f(): string; +interface M { + f(): string; } var M: M; @@ -762,13 +762,13 @@ The interface 'M' summarizes the externally visible behavior of namespace 'M'. I The TypeScript compiler emits the following JavaScript code for the namespace: ```TypeScript -var M; -(function(M) { - var s = "hello"; - function f() { - return s; - } - M.f = f; +var M; +(function(M) { + var s = "hello"; + function f() { + return s; + } + M.f = f; })(M || (M = {})); ``` @@ -788,10 +788,10 @@ The remainder of this document is the formal specification of the TypeScript pro The syntactic grammar added by TypeScript language is specified throughout this document using the existing conventions and production names of the ECMAScript grammar. In places where TypeScript augments an existing grammar production it is so noted. For example: -  *Declaration:* *( Modified )* -   … -   *InterfaceDeclaration* -   *TypeAliasDeclaration* +  *Declaration:* *( Modified )* +   … +   *InterfaceDeclaration* +   *TypeAliasDeclaration*    *EnumDeclaration* The '*( Modified )*' annotation indicates that an existing grammar production is being replaced, and the '…' references the contents of the original grammar production. @@ -814,56 +814,55 @@ Most commonly, names are written to conform with the *Identifier* production, wh The following keywords are reserved and cannot be used as an *Identifier*: ```TypeScript -break case catch class -const continue debugger default -delete do else enum -export extends false finally -for function if import -in instanceof new null -return super switch this -throw true try typeof +break case catch class +const continue debugger default +delete do else enum +export extends false finally +for function if import +in instanceof new null +return super switch this +throw true try typeof var void while with ``` The following keywords cannot be used as identifiers in strict mode code, but are otherwise not restricted: ```TypeScript -implements interface let package -private protected public static +implements interface let package +private protected public static yield ``` The following keywords cannot be used as user defined type names, but are otherwise not restricted: ```TypeScript -any boolean number string +any boolean number string symbol ``` The following keywords have special meaning in certain contexts, but are valid identifiers: ```TypeScript -abstract as async await -constructor declare from get -is module namespace of -override readonly require set -type +abstract as async await +constructor declare from get +is module namespace of +require set type ``` ### 2.2.2 Property Names The *PropertyName* production from the ECMAScript grammar is reproduced below: -  *PropertyName:* -   *LiteralPropertyName* +  *PropertyName:* +   *LiteralPropertyName*    *ComputedPropertyName* -  *LiteralPropertyName:* -   *IdentifierName* -   *StringLiteral* +  *LiteralPropertyName:* +   *IdentifierName* +   *StringLiteral*    *NumericLiteral* -  *ComputedPropertyName:* +  *ComputedPropertyName:*    `[` *AssignmentExpression* `]` A property name can be any identifier (including a reserved word), a string literal, a numeric literal, or a computed property name. String literals may be used to give properties names that are not valid identifiers, such as names containing blanks. Numeric literal property names are equivalent to string literal property names with the string representation of the numeric literal, as defined in the ECMAScript specification. @@ -883,8 +882,8 @@ In a *PropertyName* that specifies a *ComputedPropertyName*, the computed proper Below is an example of an interface that declares a property with a well-known symbol name: ```TypeScript -interface Iterable { - [Symbol.iterator](): Iterator; +interface Iterable { + [Symbol.iterator](): Iterator; } ``` @@ -899,8 +898,8 @@ var X: string; // Value named X type X = number; // Type named X -namespace X { // Namespace named X - type Y = string; +namespace X { // Namespace named X + type Y = string; } ``` @@ -909,7 +908,7 @@ A name that denotes a value has an associated type (section [3](#3)) and can be When a name with multiple meanings is referenced, the context in which the reference occurs determines the meaning. For example: ```TypeScript -var n: X; // X references type +var n: X; // X references type var s: X.Y = X; // First X references namespace, second X references value ``` @@ -927,12 +926,12 @@ Declarations introduce the following meanings for the name they declare: Below are some examples of declarations that introduce multiple meanings for a name: ```TypeScript -class C { // Value and type named C - x: string; +class C { // Value and type named C + x: string; } -namespace N { // Value and namespace named N - export var x: string; +namespace N { // Value and namespace named N + export var x: string; } ``` @@ -971,9 +970,9 @@ Interfaces, enums, and namespaces are "open ended," meaning that interface, enum Instance and static members in a class are in separate declaration spaces. Thus the following is permitted: ```TypeScript -class C { - x: number; // Instance member - static x: string; // Static member +class C { + x: number; // Instance member + static x: string; // Static member } ``` @@ -1009,17 +1008,17 @@ Note that class and interface members are never directly in scope—they can onl As the rules above imply, locally declared entities in a namespace are closer in scope than exported entities declared in other namespace declarations for the same namespace. For example: ```TypeScript -var x = 1; -namespace M { - export var x = 2; - console.log(x); // 2 -} -namespace M { - console.log(x); // 2 -} -namespace M { - var x = 3; - console.log(x); // 3 +var x = 1; +namespace M { + export var x = 2; + console.log(x); // 2 +} +namespace M { + console.log(x); // 2 +} +namespace M { + var x = 3; + console.log(x); // 3 } ``` @@ -1062,12 +1061,12 @@ The Any type is a supertype of all types, and is assignable to and from all type Some examples: ```TypeScript -var x: any; // Explicitly typed -var y; // Same as y: any +var x: any; // Explicitly typed +var y; // Same as y: any var z: { a; b; }; // Same as z: { a: any; b: any; } -function f(x) { // Same as f(x: any): void - console.log(x); +function f(x) { // Same as f(x: any): void + console.log(x); } ``` @@ -1086,9 +1085,9 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var x: number; // Explicitly typed -var y = 0; // Same as y: number = 0 -var z = 123.456; // Same as z: number = 123.456 +var x: number; // Explicitly typed +var y = 0; // Same as y: number = 0 +var z = 123.456; // Same as z: number = 123.456 var s = z.toFixed(2); // Property of Number interface ``` @@ -1103,8 +1102,8 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var b: boolean; // Explicitly typed -var yes = true; // Same as yes: boolean = true +var b: boolean; // Explicitly typed +var yes = true; // Same as yes: boolean = true var no = false; // Same as no: boolean = false ``` @@ -1119,9 +1118,9 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var s: string; // Explicitly typed -var empty = ""; // Same as empty: string = "" -var abc = 'abc'; // Same as abc: string = "abc" +var s: string; // Explicitly typed +var empty = ""; // Same as empty: string = "" +var abc = 'abc'; // Same as abc: string = "abc" var c = abc.charAt(2); // Property of String interface ``` @@ -1136,9 +1135,9 @@ For purposes of determining type relationships (section [3.11](#3.11)) and acces Some examples: ```TypeScript -var secretKey = Symbol(); -var obj = {}; -obj[secretKey] = "secret message"; // Use symbol as property key +var secretKey = Symbol(); +var obj = {}; +obj[secretKey] = "secret message"; // Use symbol as property key obj[Symbol.toStringTag] = "test"; // Use of well-known symbol ``` @@ -1161,8 +1160,8 @@ The Null type is a subtype of all types, except the Undefined type. This means t Some examples: ```TypeScript -var n: number = null; // Primitives can be null -var x = null; // Same as x: any = null +var n: number = null; // Primitives can be null +var x = null; // Same as x: any = null var e: Null; // Error, can't reference Null type ``` @@ -1177,8 +1176,8 @@ The undefined type is a subtype of all types. This means that `undefined` is con Some examples: ```TypeScript -var n: number; // Same as n: number = undefined -var x = undefined; // Same as x: any = undefined +var n: number; // Same as n: number = undefined +var x = undefined; // Same as x: any = undefined var e: Undefined; // Error, can't reference Undefined type ``` @@ -1224,10 +1223,10 @@ Type references (section [3.8.2](#3.8.2)) to class and interface types are class The declaration of the 'Array' interface includes a property 'length' and a numeric index signature for the element type, along with other members: ```TypeScript -interface Array { - length: number; - [x: number]: T; - // Other members +interface Array { + length: number; + [x: number]: T; + // Other members } ``` @@ -1250,11 +1249,11 @@ A type is said to be an ***array-like type*** if it is assignable (section [3.11 combines the set of properties ```TypeScript -{ - 0: T0; - 1: T1; - ... - n: Tn; +{ + 0: T0; + 1: T1; + ... + n: Tn; } ``` @@ -1263,10 +1262,10 @@ with the members of an array type whose element type is the union type (section Array literals (section [4.6](#4.6)) may be used to create values of tuple types. For example: ```TypeScript -var t: [number, string] = [3, "three"]; -var n = t[0]; // Type of n is number -var s = t[1]; // Type of s is string -var i: number; +var t: [number, string] = [3, "three"]; +var n = t[0]; // Type of n is number +var s = t[1]; // Type of s is string +var i: number; var x = t[i]; // Type of x is number | string ``` @@ -1327,12 +1326,12 @@ Type guards (section [4.24](#4.24)) may be used to narrow a union type to a more In the example ```TypeScript -var x: string | number; -var test: boolean; -x = "hello"; // Ok -x = 42; // Ok -x = test; // Error, boolean not assignable -x = test ? 5 : "five"; // Ok +var x: string | number; +var test: boolean; +x = "hello"; // Ok +x = 42; // Ok +x = test; // Error, boolean not assignable +x = test ? 5 : "five"; // Ok x = test ? 0 : false; // Error, number | boolean not assignable ``` @@ -1345,20 +1344,20 @@ var n = typeof x === "string" ? x.length : x; // Type of n is number For purposes of property access and function calls, the apparent members (section [3.11.1](#3.11.1)) of a union type are those that are present in every one of its constituent types, with types that are unions of the respective apparent members in the constituent types. The following example illustrates the merging of member types that occurs when union types are created from object types. ```TypeScript -interface A { - a: string; - b: number; +interface A { + a: string; + b: number; } -interface B { - a: number; - b: number; - c: number; +interface B { + a: number; + b: number; + c: number; } -var x: A | B; -var a = x.a; // a has type string | number -var b = x.b; // b has type number +var x: A | B; +var a = x.a; // a has type string | number +var b = x.b; // b has type number var c = x.c; // Error, no property c in union type ``` @@ -1385,36 +1384,36 @@ Similarly, intersection types have the following assignability relationships: For purposes of property access and function calls, the apparent members (section [3.11.1](#3.11.1)) of an intersection type are those that are present in one or more of its constituent types, with types that are intersections of the respective apparent members in the constituent types. The following examples illustrate the merging of member types that occurs when intersection types are created from object types. ```TypeScript -interface A { a: number } +interface A { a: number } interface B { b: number } -var ab: A & B = { a: 1, b: 1 }; -var a: A = ab; // A & B assignable to A +var ab: A & B = { a: 1, b: 1 }; +var a: A = ab; // A & B assignable to A var b: B = ab; // A & B assignable to B -interface X { p: A } +interface X { p: A } interface Y { p: B } var xy: X & Y = { p: ab }; // X & Y has property p of type A & B -type F1 = (a: string, b: string) => void; +type F1 = (a: string, b: string) => void; type F2 = (a: number, b: number) => void; -var f: F1 & F2 = (a: string | number, b: string | number) => { }; -f("hello", "world"); // Ok -f(1, 2); // Ok +var f: F1 & F2 = (a: string | number, b: string | number) => { }; +f("hello", "world"); // Ok +f(1, 2); // Ok f(1, "test"); // Error ``` The union and intersection type operators can be applied to type parameters. This capability can for example be used to model functions that merge objects: ```TypeScript -function extend(first: T, second: U): T & U { - // Extend first with properties of second +function extend(first: T, second: U): T & U { + // Extend first with properties of second } -var x = extend({ a: "hello" }, { b: 42 }); -var s = x.a; +var x = extend({ a: "hello" }, { b: 42 }); +var s = x.a; var n = x.b; ``` @@ -1430,17 +1429,17 @@ Since a type parameter represents a multitude of different type arguments, type Class, interface, type alias, and function declarations may optionally include lists of type parameters enclosed in < and > brackets. Type parameters are also permitted in call signatures of object, function, and constructor type literals. -  *TypeParameters:* +  *TypeParameters:*    `<` *TypeParameterList* `>` -  *TypeParameterList:* -   *TypeParameter* +  *TypeParameterList:* +   *TypeParameter*    *TypeParameterList* `,` *TypeParameter* -  *TypeParameter:* +  *TypeParameter:*    *BindingIdentifier* *Constraintopt* -  *Constraint:* +  *Constraint:*    `extends` *Type* Type parameter names must be unique. A compile-time error occurs if two or more type parameters in the same *TypeParameterList* have the same name. @@ -1477,14 +1476,14 @@ interface B { } A type reference (section [3.8.2](#3.8.2)) to a generic type must include a list of type arguments enclosed in angle brackets and separated by commas. Similarly, a call (section [4.15](#4.15)) to a generic function may explicitly include a type argument list instead of relying on type inference. -  *TypeArguments:* +  *TypeArguments:*    `<` *TypeArgumentList* `>` -  *TypeArgumentList:* -   *TypeArgument* +  *TypeArgumentList:* +   *TypeArgument*    *TypeArgumentList* `,` *TypeArgument* -  *TypeArgument:* +  *TypeArgument:*    *Type* Type arguments correspond one-to-one with type parameters of the generic type or function being referenced. A type argument list is required to specify exactly one type argument for each corresponding type parameter, and each type argument for a constrained type parameter is required to ***satisfy*** the constraint of that type parameter. A type argument satisfies a type parameter constraint if the type argument is assignable to (section [3.11.4](#3.11.4)) the constraint type once type arguments are substituted for type parameters. @@ -1506,19 +1505,19 @@ Every class and interface has a ***this-type*** that represents the actual type Classes and interfaces support inheritance and therefore the instance represented by `this` in a method isn't necessarily an instance of the containing class—it may in fact be an instance of a derived class or interface. To model this relationship, the this-type of a class or interface is classified as a type parameter. Unlike other type parameters, it is not possible to explicitly pass a type argument for a this-type. Instead, in a type reference to a class or interface type, the type reference *itself* is implicitly passed as a type argument for the this-type. For example: ```TypeScript -class A { - foo() { - return this; - } +class A { + foo() { + return this; + } } -class B extends A { - bar() { - return this; - } +class B extends A { + bar() { + return this; + } } -let b: B; +let b: B; let x = b.foo().bar(); // Fluent pattern works, type of x is B ``` @@ -1558,37 +1557,37 @@ is indistinguishable from the type Types are specified either by referencing their keyword or name, or by writing object type literals, array type literals, tuple type literals, function type literals, constructor type literals, or type queries. -  *Type:* -   *UnionOrIntersectionOrPrimaryType* -   *FunctionType* +  *Type:* +   *UnionOrIntersectionOrPrimaryType* +   *FunctionType*    *ConstructorType* -  *UnionOrIntersectionOrPrimaryType:* -   *UnionType* +  *UnionOrIntersectionOrPrimaryType:* +   *UnionType*    *IntersectionOrPrimaryType* -  *IntersectionOrPrimaryType:* -   *IntersectionType* +  *IntersectionOrPrimaryType:* +   *IntersectionType*    *PrimaryType* -  *PrimaryType:* -   *ParenthesizedType* -   *PredefinedType* -   *TypeReference* -   *ObjectType* -   *ArrayType* -   *TupleType* -   *TypeQuery* +  *PrimaryType:* +   *ParenthesizedType* +   *PredefinedType* +   *TypeReference* +   *ObjectType* +   *ArrayType* +   *TupleType* +   *TypeQuery*    *ThisType* -  *ParenthesizedType:* +  *ParenthesizedType:*    `(` *Type* `)` Parentheses are required around union, intersection, function, or constructor types when they are used as array element types; around union, function, or constructor types in intersection types; and around function or constructor types in union types. For example: ```TypeScript -(string | number)[] -((x: string) => string) | ((x: number) => number) +(string | number)[] +((x: string) => string) | ((x: number) => number) (A | B) & (C | D) ``` @@ -1598,12 +1597,12 @@ The different forms of type notations are described in the following sections. The `any`, `number`, `boolean`, `string`, `symbol` and `void` keywords reference the Any type and the Number, Boolean, String, Symbol, and Void primitive types respectively. -  *PredefinedType:* -   `any` -   `number` -   `boolean` -   `string` -   `symbol` +  *PredefinedType:* +   `any` +   `number` +   `boolean` +   `string` +   `symbol`    `void` The predefined type keywords are reserved and cannot be used as names of user defined types. @@ -1612,15 +1611,15 @@ The predefined type keywords are reserved and cannot be used as names of user de A type reference references a named type or type parameter through its name and, in the case of a generic type, supplies a type argument list. -  *TypeReference:* +  *TypeReference:*    *TypeName* *[no LineTerminator here]* *TypeArgumentsopt* -  *TypeName:* -   *IdentifierReference* +  *TypeName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* -  *NamespaceName:* -   *IdentifierReference* +  *NamespaceName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* A *TypeReference* consists of a *TypeName* that a references a named type or type parameter. A reference to a generic type must be followed by a list of *TypeArguments* (section [3.6.2](#3.6.2)). @@ -1644,17 +1643,17 @@ interface B extends A { b: string; } interface C extends B { c: string; } -interface G { - x: T; - y: U; +interface G { + x: T; + y: U; } -var v1: G; // Ok -var v2: G<{ a: string }, C>; // Ok, equivalent to G -var v3: G; // Error, A not valid argument for U -var v4: G, C>; // Ok -var v5: G; // Ok -var v6: G; // Error, wrong number of arguments +var v1: G; // Ok +var v2: G<{ a: string }, C>; // Ok, equivalent to G +var v3: G; // Error, A not valid argument for U +var v4: G, C>; // Ok +var v5: G; // Ok +var v6: G; // Error, wrong number of arguments var v7: G; // Error, no arguments ``` @@ -1663,9 +1662,9 @@ A type argument is simply a *Type* and may itself be a type reference to a gener As described in section [3.7](#3.7), a type reference to a generic type *G* designates a type wherein all occurrences of *G*'s type parameters have been replaced with the actual type arguments supplied in the type reference. For example, the declaration of 'v1' above is equivalent to: ```TypeScript -var v1: { - x: { a: string; } - y: { a: string; b: string; c: string }; +var v1: { + x: { a: string; } + y: { a: string; b: string; c: string }; }; ``` @@ -1673,23 +1672,23 @@ var v1: { An object type literal defines an object type by specifying the set of members that are statically considered to be present in instances of the type. Object type literals can be given names using interface declarations but are otherwise anonymous. -  *ObjectType:* +  *ObjectType:*    `{` *TypeBodyopt* `}` -  *TypeBody:* -   *TypeMemberList* `;`*opt* +  *TypeBody:* +   *TypeMemberList* `;`*opt*    *TypeMemberList* `,`*opt* -  *TypeMemberList:* -   *TypeMember* -   *TypeMemberList* `;` *TypeMember* +  *TypeMemberList:* +   *TypeMember* +   *TypeMemberList* `;` *TypeMember*    *TypeMemberList* `,` *TypeMember* -  *TypeMember:* -   *PropertySignature* -   *CallSignature* -   *ConstructSignature* -   *IndexSignature* +  *TypeMember:* +   *PropertySignature* +   *CallSignature* +   *ConstructSignature* +   *IndexSignature*    *MethodSignature* The members of an object type literal are specified as a combination of property, call, construct, index, and method signatures. Object type members are described in section [3.9](#3.9). @@ -1698,7 +1697,7 @@ The members of an object type literal are specified as a combination of property An array type literal is written as an element type followed by an open and close square bracket. -  *ArrayType:* +  *ArrayType:*    *PrimaryType* *[no LineTerminator here]* `[` `]` An array type literal references an array type (section [3.3.2](#3.3.2)) with the given element type. An array type literal is simply shorthand notation for a reference to the generic interface type 'Array' in the global namespace with the element type as a type argument. @@ -1706,14 +1705,14 @@ An array type literal references an array type (section [3.3.2](#3.3.2)) with th When union, intersection, function, or constructor types are used as array element types they must be enclosed in parentheses. For example: ```TypeScript -(string | number)[] +(string | number)[] (() => string))[] ``` Alternatively, array types can be written using the 'Array<T>' notation. For example, the types above are equivalent to ```TypeScript -Array +Array Array<() => string> ``` @@ -1721,14 +1720,14 @@ Array<() => string> A tuple type literal is written as a sequence of element types, separated by commas and enclosed in square brackets. -  *TupleType:* +  *TupleType:*    `[` *TupleElementTypes* `]` -  *TupleElementTypes:* -   *TupleElementType* +  *TupleElementTypes:* +   *TupleElementType*    *TupleElementTypes* `,` *TupleElementType* -  *TupleElementType:* +  *TupleElementType:*    *Type* A tuple type literal references a tuple type (section [3.3.3](#3.3.3)). @@ -1737,7 +1736,7 @@ A tuple type literal references a tuple type (section [3.3.3](#3.3.3)). A union type literal is written as a sequence of types separated by vertical bars. -  *UnionType:* +  *UnionType:*    *UnionOrIntersectionOrPrimaryType* `|` *IntersectionOrPrimaryType* A union type literal references a union type (section [3.4](#3.4)). @@ -1746,7 +1745,7 @@ A union type literal references a union type (section [3.4](#3.4)). An intersection type literal is written as a sequence of types separated by ampersands. -  *IntersectionType:* +  *IntersectionType:*    *IntersectionOrPrimaryType* `&` *PrimaryType* An intersection type literal references an intersection type (section [3.5](#3.5)). @@ -1755,7 +1754,7 @@ An intersection type literal references an intersection type (section [3.5](#3.5 A function type literal specifies the type parameters, regular parameters, and return type of a call signature. -  *FunctionType:* +  *FunctionType:*    *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* A function type literal is shorthand for an object type containing a single call signature. Specifically, a function type literal of the form @@ -1776,7 +1775,7 @@ Note that function types with multiple call or construct signatures cannot be wr A constructor type literal specifies the type parameters, regular parameters, and return type of a construct signature. -  *ConstructorType:* +  *ConstructorType:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* A constructor type literal is shorthand for an object type containing a single construct signature. Specifically, a constructor type literal of the form @@ -1797,11 +1796,11 @@ Note that constructor types with multiple construct signatures cannot be written A type query obtains the type of an expression. -  *TypeQuery:* +  *TypeQuery:*    `typeof` *TypeQueryExpression* -  *TypeQueryExpression:* -   *IdentifierReference* +  *TypeQueryExpression:* +   *IdentifierReference*    *TypeQueryExpression* `.` *IdentifierName* A type query consists of the keyword `typeof` followed by an expression. The expression is restricted to a single identifier or a sequence of identifiers separated by periods. The expression is processed as an identifier expression (section [4.3](#4.3)) or property access expression (section [4.13](#4.13)), the widened type (section [3.12](#3.12)) of which becomes the result. Similar to other static typing constructs, type queries are erased from the generated JavaScript code and add no run-time overhead. @@ -1809,7 +1808,7 @@ A type query consists of the keyword `typeof` followed by an expression. The exp Type queries are useful for capturing anonymous types that are generated by various constructs such as object literals, function declarations, and namespace declarations. For example: ```TypeScript -var a = { x: 10, y: 20 }; +var a = { x: 10, y: 20 }; var b: typeof a; ``` @@ -1818,16 +1817,16 @@ Above, 'b' is given the same type as 'a', namely `{ x: number; y: number; }`. If a declaration includes a type annotation that references the entity being declared through a circular path of type queries or type references containing type queries, the resulting type is the Any type. For example, all of the following variables are given the type Any: ```TypeScript -var c: typeof c; -var d: typeof e; -var e: typeof d; +var c: typeof c; +var d: typeof e; +var e: typeof d; var f: Array; ``` However, if a circular path of type queries includes at least one *ObjectType*, *FunctionType* or *ConstructorType*, the construct denotes a recursive type: ```TypeScript -var g: { x: typeof g; }; +var g: { x: typeof g; }; var h: () => typeof h; ``` @@ -1837,7 +1836,7 @@ Here, 'g' and 'g.x' have the same recursive type, and likewise 'h' and 'h()' hav The `this` keyword is used to reference the this-type (section [3.6.3](#3.6.3)) of a class or interface. -  *ThisType:* +  *ThisType:*    `this` The meaning of a *ThisType* depends on the closest enclosing *FunctionDeclaration*, *FunctionExpression*, *PropertyDefinition*, *ClassElement*, or *TypeMember*, known as the root declaration of the *ThisType*, as follows: @@ -1849,10 +1848,10 @@ The meaning of a *ThisType* depends on the closest enclosing *FunctionDeclaratio Note that in order to avoid ambiguities it is not possible to reference the this-type of a class or interface in a nested object type literal. In the example ```TypeScript -interface ListItem { - getHead(): this; - getTail(): this; - getHeadAndTail(): { head: this, tail: this }; // Error +interface ListItem { + getHead(): this; + getTail(): this; + getHeadAndTail(): { head: this, tail: this }; // Error } ``` @@ -1861,25 +1860,25 @@ the `this` references on the last line are in error because their root declarati ```TypeScript type HeadAndTail = { head: T, tail: T }; -interface ListItem { - getHead(): this; - getTail(): this; - getHeadAndTail(): HeadAndTail; +interface ListItem { + getHead(): this; + getTail(): this; + getHeadAndTail(): HeadAndTail; } ``` ## 3.9 Specifying Members -The members of an object type literal (section [3.8.3](#3.8.3)) are specified as a combination of property, call, construct, index, and method signatures. +The members of an object type literal (section [3.8.3](#3.8.3)) are specified as a combination of property, call, construct, index, and method signatures. ### 3.9.1 Property Signatures A property signature declares the name and type of a property member. -  *PropertySignature:* +  *PropertySignature:*    *PropertyName* `?`*opt* *TypeAnnotationopt* -  *TypeAnnotation:* +  *TypeAnnotation:*    `:` *Type* The *PropertyName* ([2.2.2](#2.2.2)) of a property signature must be unique within its containing type, and must denote a well-known symbol if it is a computed property name ([2.2.3](#2.2.3)). If the property name is followed by a question mark, the property is optional. Otherwise, the property is required. @@ -1890,7 +1889,7 @@ If a property signature omits a *TypeAnnotation*, the Any type is assumed. A call signature defines the type parameters, parameter list, and return type associated with applying a call operation (section [4.15](#4.15)) to an instance of the containing type. A type may ***overload*** call operations by defining multiple different call signatures. -  *CallSignature:* +  *CallSignature:*    *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* A call signature that includes *TypeParameters* (section [3.6.1](#3.6.1)) is called a ***generic call signature***. Conversely, a call signature with no *TypeParameters* is called a non-generic call signature. @@ -1937,42 +1936,42 @@ A function taking an array of one type and a function argument, returning an arr A signature's parameter list consists of zero or more required parameters, followed by zero or more optional parameters, finally followed by an optional rest parameter. -  *ParameterList:* -   *RequiredParameterList* -   *OptionalParameterList* -   *RestParameter* -   *RequiredParameterList* `,` *OptionalParameterList* -   *RequiredParameterList* `,` *RestParameter* -   *OptionalParameterList* `,` *RestParameter* +  *ParameterList:* +   *RequiredParameterList* +   *OptionalParameterList* +   *RestParameter* +   *RequiredParameterList* `,` *OptionalParameterList* +   *RequiredParameterList* `,` *RestParameter* +   *OptionalParameterList* `,` *RestParameter*    *RequiredParameterList* `,` *OptionalParameterList* `,` *RestParameter* -  *RequiredParameterList:* -   *RequiredParameter* +  *RequiredParameterList:* +   *RequiredParameter*    *RequiredParameterList* `,` *RequiredParameter* -  *RequiredParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* +  *RequiredParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt*    *BindingIdentifier* `:` *StringLiteral* -  *AccessibilityModifier:* -   `public` -   `private` +  *AccessibilityModifier:* +   `public` +   `private`    `protected` -  *BindingIdentifierOrPattern:* -   *BindingIdentifier* +  *BindingIdentifierOrPattern:* +   *BindingIdentifier*    *BindingPattern* -  *OptionalParameterList:* -   *OptionalParameter* +  *OptionalParameterList:* +   *OptionalParameter*    *OptionalParameterList* `,` *OptionalParameter* -  *OptionalParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer* +  *OptionalParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer*    *BindingIdentifier* `?` `:` *StringLiteral* -  *RestParameter:* +  *RestParameter:*    `...` *BindingIdentifier* *TypeAnnotationopt* A parameter declaration may specify either an identifier or a binding pattern ([5.2.2](#5.2.2)). The identifiers specified in parameter declarations and binding patterns in a parameter list must be unique within that parameter list. @@ -2010,11 +2009,11 @@ When a call signature with no return type annotation occurs in a context that ha When a parameter type annotation specifies a string literal type (section [3.2.9](#3.2.9)), the containing signature is considered a specialized signature. Specialized signatures are used to express patterns where specific string values for some parameters cause the types of other parameters or the function result to become further specialized. For example, the declaration ```TypeScript -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; - createElement(tagName: string): HTMLElement; +interface Document { + createElement(tagName: "div"): HTMLDivElement; + createElement(tagName: "span"): HTMLSpanElement; + createElement(tagName: "canvas"): HTMLCanvasElement; + createElement(tagName: string): HTMLElement; } ``` @@ -2028,7 +2027,7 @@ Every specialized call or construct signature in an object type must be assignab A construct signature defines the parameter list and return type associated with applying the `new` operator (section [4.14](#4.14)) to an instance of the containing type. A type may overload `new` operations by defining multiple construct signatures with different parameter lists. -  *ConstructSignature:* +  *ConstructSignature:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* The type parameters, parameter list, and return type of a construct signature are subject to the same rules as a call signature. @@ -2039,8 +2038,8 @@ A type containing construct signatures is said to be a ***constructor type***. An index signature defines a type constraint for properties in the containing type. -  *IndexSignature:* -   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation* +  *IndexSignature:* +   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation*    `[` *BindingIdentifier* `:` `number` `]` *TypeAnnotation* There are two kinds of index signatures: @@ -2058,7 +2057,7 @@ Index signatures affect the determination of the type that results from applying A method signature is shorthand for declaring a property of a function type. -  *MethodSignature:* +  *MethodSignature:*    *PropertyName* `?`*opt* *CallSignature* If the *PropertyName* is a computed property name ([2.2.3](#2.2.3)), it must specify a well-known symbol. If the *PropertyName* is followed by a question mark, the property is optional. Otherwise, the property is required. Only object type literals and interfaces can declare optional properties. @@ -2078,41 +2077,41 @@ f : { < T1, T2, ... > ( p1, p2, ... ) : R } A literal type may ***overload*** a method by declaring multiple method signatures with the same name but differing parameter lists. Overloads must either all be required (question mark omitted) or all be optional (question mark included). A set of overloaded method signatures correspond to a declaration of a single property with a type composed from an equivalent set of call signatures. Specifically ```TypeScript -f < T1, T2, ... > ( p1, p2, ... ) : R ; -f < U1, U2, ... > ( q1, q2, ... ) : S ; +f < T1, T2, ... > ( p1, p2, ... ) : R ; +f < U1, U2, ... > ( q1, q2, ... ) : S ; ... ``` is equivalent to ```TypeScript -f : { - < T1, T2, ... > ( p1, p2, ... ) : R ; - < U1, U2, ... > ( q1, q2, ... ) : S ; - ... +f : { + < T1, T2, ... > ( p1, p2, ... ) : R ; + < U1, U2, ... > ( q1, q2, ... ) : S ; + ... } ; ``` In the following example of an object type ```TypeScript -{ - func1(x: number): number; // Method signature - func2: (x: number) => number; // Function type literal - func3: { (x: number): number }; // Object type literal +{ + func1(x: number): number; // Method signature + func2: (x: number) => number; // Function type literal + func3: { (x: number): number }; // Object type literal } ``` the properties 'func1', 'func2', and 'func3' are all of the same type, namely an object type with a single call signature taking a number and returning a number. Likewise, in the object type ```TypeScript -{ - func4(x: number): number; - func4(s: string): string; - func5: { - (x: number): number; - (s: string): string; - }; +{ + func4(x: number): number; + func4(s: string): string; + func5: { + (x: number): number; + (s: string): string; + }; } ``` @@ -2122,7 +2121,7 @@ the properties 'func4' and 'func5' are of the same type, namely an object type w A type alias declaration introduces a ***type alias*** in the containing declaration space. -  *TypeAliasDeclaration:* +  *TypeAliasDeclaration:*    `type` *BindingIdentifier* *TypeParametersopt* `=` *Type* `;` A type alias serves as an alias for the type specified in the type alias declaration. Unlike an interface declaration, which always introduces a named object type, a type alias declaration can introduce a name for any kind of type, including primitive, union, and intersection types. @@ -2147,31 +2146,31 @@ Given this definition, the complete set of types upon which a type depends is th Some examples of type alias declarations: ```TypeScript -type StringOrNumber = string | number; -type Text = string | { text: string }; -type NameLookup = Dictionary; -type ObjectStatics = typeof Object; -type Callback = (data: T) => void; -type Pair = [T, T]; -type Coordinates = Pair; +type StringOrNumber = string | number; +type Text = string | { text: string }; +type NameLookup = Dictionary; +type ObjectStatics = typeof Object; +type Callback = (data: T) => void; +type Pair = [T, T]; +type Coordinates = Pair; type Tree = T | { left: Tree, right: Tree }; ``` Interface types have many similarities to type aliases for object type literals, but since interface types offer more capabilities they are generally preferred to type aliases. For example, the interface type ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } ``` could be written as the type alias ```TypeScript -type Point = { - x: number; - y: number; +type Point = { + x: number; + y: number; }; ``` @@ -2216,8 +2215,8 @@ In effect, a type's apparent members make it a subtype of the 'Object' or 'Funct Some examples: ```TypeScript -var o: Object = { x: 10, y: 20 }; // Ok -var f: Function = (x: number) => x * x; // Ok +var o: Object = { x: 10, y: 20 }; // Ok +var f: Function = (x: number) => x * x; // Ok var err: Object = { toString: 0 }; // Error ``` @@ -2255,7 +2254,7 @@ interface X { f(): string; } interface Y { f(): string; } -var a: C; +var a: C; var b: C; ``` @@ -2343,9 +2342,9 @@ The assignment compatibility rules imply that, when assigning values or passing ```TypeScript function foo(x: { id: number; name?: string; }) { } -foo({ id: 1234 }); // Ok -foo({ id: 1234, name: "hello" }); // Ok -foo({ id: 1234, name: false }); // Error, name of wrong type +foo({ id: 1234 }); // Ok +foo({ id: 1234, name: "hello" }); // Ok +foo({ id: 1234, name: false }); // Error, name of wrong type foo({ name: "hello" }); // Error, id required but missing ``` @@ -2373,16 +2372,16 @@ The type inferred for an object literal (as described in section [4.5](#4.5)) is Consider the following example: ```TypeScript -interface CompilerOptions { - strict?: boolean; - sourcePath?: string; - targetPath?: string; +interface CompilerOptions { + strict?: boolean; + sourcePath?: string; + targetPath?: string; } -var options: CompilerOptions = { - strict: true, - sourcepath: "./src", // Error, excess or misspelled property - targetpath: "./bin" // Error, excess or misspelled property +var options: CompilerOptions = { + strict: true, + sourcepath: "./src", // Error, excess or misspelled property + targetpath: "./bin" // Error, excess or misspelled property }; ``` @@ -2391,17 +2390,17 @@ The 'CompilerOptions' type contains only optional properties, so without the exc In cases where excess properties are expected, an index signature can be added to the target type as an indicator of intent: ```TypeScript -interface InputElement { - name: string; - visible?: boolean; - [x: string]: any; // Allow additional properties of any type +interface InputElement { + name: string; + visible?: boolean; + [x: string]: any; // Allow additional properties of any type } -var address: InputElement = { - name: "Address", - visible: true, - help: "Enter address here", // Allowed because of index signature - shortcut: "Alt-A" // Allowed because of index signature +var address: InputElement = { + name: "Address", + visible: true, + help: "Enter address here", // Allowed because of index signature + shortcut: "Alt-A" // Allowed because of index signature }; ``` @@ -2460,10 +2459,10 @@ When this same technique is used to compare generic type references, two type re In certain circumstances, generic types that directly or indirectly reference themselves in a recursive fashion can lead to infinite series of distinct instantiations. For example, in the type ```TypeScript -interface List { - data: T; - next: List; - owner: List>; +interface List { + data: T; + next: List; + owner: List>; } ``` @@ -2482,9 +2481,9 @@ infers the type of 'name' to be the String primitive type since that is the type The following example shows the results of widening types to produce inferred variable types. ```TypeScript -var a = null; // var a: any -var b = undefined; // var b: any -var c = { x: 0, y: null }; // var c: { x: number, y: any } +var a = null; // var a: any +var b = undefined; // var b: any +var c = { x: 0, y: null }; // var c: { x: number, y: any } var d = [ null, undefined ]; // var d: any[] ``` @@ -2548,18 +2547,18 @@ Literals are typed as follows: Object literals are extended to support type annotations in methods and get and set accessors. -  *PropertyDefinition:* *( Modified )* -   *IdentifierReference* -   *CoverInitializedName* -   *PropertyName* `:` *AssignmentExpression* -   *PropertyName* *CallSignature* `{` *FunctionBody* `}` -   *GetAccessor* +  *PropertyDefinition:* *( Modified )* +   *IdentifierReference* +   *CoverInitializedName* +   *PropertyName* `:` *AssignmentExpression* +   *PropertyName* *CallSignature* `{` *FunctionBody* `}` +   *GetAccessor*    *SetAccessor* -  *GetAccessor:* +  *GetAccessor:*    `get` *PropertyName* `(` `)` *TypeAnnotationopt* `{` *FunctionBody* `}` -  *SetAccessor:* +  *SetAccessor:*    `set` *PropertyName* `(` *BindingIdentifierOrPattern* *TypeAnnotationopt* `)` `{` *FunctionBody* `}` The type of an object literal is an object type with the set of properties specified by the property assignments in the object literal. A get and set accessor may specify the same property name, but otherwise it is an error to specify multiple property assignments for the same property. @@ -2645,22 +2644,22 @@ A spread element must specify an expression of an array-like type (section [3.3. The rules above mean that an array literal is always of an array type, unless it is contextually typed by a tuple-like type. For example ```TypeScript -var a = [1, 2]; // number[] -var b = ["hello", true]; // (string | boolean)[] +var a = [1, 2]; // number[] +var b = ["hello", true]; // (string | boolean)[] var c: [number, string] = [3, "three"]; // [number, string] ``` When the output target is ECMAScript 3 or 5, array literals containing spread elements are rewritten to invocations of the `concat` method. For example, the assignments ```TypeScript -var a = [2, 3, 4]; +var a = [2, 3, 4]; var b = [0, 1, ...a, 5, 6]; ``` are rewritten to ```TypeScript -var a = [2, 3, 4]; +var a = [2, 3, 4]; var b = [0, 1].concat(a, [5, 6]); ``` @@ -2711,7 +2710,7 @@ The JavaScript code generated for a super property access is specified in sectio Function expressions are extended from JavaScript to optionally include parameter and return type annotations. -  *FunctionExpression:* *( Modified )* +  *FunctionExpression:* *( Modified )*    `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` The descriptions of function declarations provided in chapter [6](#6) apply to function expressions as well, except that function expressions do not support overloading. @@ -2731,8 +2730,8 @@ A contextual signature *S* is extracted from a function type *T* as follows: In the example ```TypeScript -var f: (s: string) => string = function (s) { - return s.toLowerCase(); +var f: (s: string) => string = function (s) { + return s.toLowerCase(); }; ``` @@ -2742,7 +2741,7 @@ the function expression is contextually typed by the type of 'f', and since the Arrow functions are extended from JavaScript to optionally include parameter and return type annotations. -  *ArrowFormalParameters:* *( Modified )* +  *ArrowFormalParameters:* *( Modified )*    *CallSignature* The descriptions of function declarations provided in chapter [6](#6) apply to arrow functions as well, except that arrow functions do not support overloading. @@ -2766,23 +2765,23 @@ is exactly equivalent to Furthermore, arrow function expressions of the forms ```TypeScript -id => { ... } +id => { ... } id => expr ``` are exactly equivalent to ```TypeScript -( id ) => { ... } +( id ) => { ... } ( id ) => expr ``` Thus, the following examples are all equivalent: ```TypeScript -(x) => { return Math.sin(x); } -(x) => Math.sin(x) -x => { return Math.sin(x); } +(x) => { return Math.sin(x); } +(x) => Math.sin(x) +x => { return Math.sin(x); } x => Math.sin(x) ``` @@ -2791,29 +2790,29 @@ A function expression introduces a new dynamically bound `this`, whereas an arro In the example ```TypeScript -class Messenger { - message = "Hello World"; - start() { - setTimeout(() => alert(this.message), 3000); - } +class Messenger { + message = "Hello World"; + start() { + setTimeout(() => alert(this.message), 3000); + } }; -var messenger = new Messenger(); +var messenger = new Messenger(); messenger.start(); ``` the use of an arrow function expression causes the callback to have the same `this` as the surrounding 'start' method. Writing the callback as a standard function expression it becomes necessary to manually arrange access to the surrounding `this`, for example by copying it into a local variable: ```TypeScript -class Messenger { - message = "Hello World"; - start() { - var _this = this; - setTimeout(function() { alert(_this.message); }, 3000); - } +class Messenger { + message = "Hello World"; + start() { + var _this = this; + setTimeout(function() { alert(_this.message); }, 3000); + } }; -var messenger = new Messenger(); +var messenger = new Messenger(); messenger.start(); ``` @@ -2870,20 +2869,20 @@ where *object* and *index* are expressions, is used to access the property with The rules above mean that properties are strongly typed when accessed using bracket notation with the literal representation of their name. For example: ```TypeScript -var type = { - name: "boolean", - primitive: true +var type = { + name: "boolean", + primitive: true }; -var s = type["name"]; // string +var s = type["name"]; // string var b = type["primitive"]; // boolean ``` Tuple types assign numeric names to each of their elements and elements are therefore strongly typed when accessed using bracket notation with a numeric literal: ```TypeScript -var data: [string, number] = ["five", 5]; -var s = data[0]; // string +var data: [string, number] = ["five", 5]; +var s = data[0]; // string var n = data[1]; // number ``` @@ -2892,8 +2891,8 @@ var n = data[1]; // number A `new` operation has one of the following forms: ```TypeScript -new C -new C ( ... ) +new C +new C ( ... ) new C < ... > ( ... ) ``` @@ -2907,13 +2906,13 @@ where *C* is an expression. The first form is equivalent to supplying an empty a Function calls are extended from JavaScript to support optional type arguments. -  *Arguments:* *( Modified )* +  *Arguments:* *( Modified )*    *TypeArgumentsopt* `(` *ArgumentListopt* `)` A function call takes one of the forms ```TypeScript -func ( ... ) +func ( ... ) func < ... > ( ... ) ``` @@ -2980,11 +2979,11 @@ The process of inferentially typing an expression *e* by a type *T* is the same An example: ```TypeScript -function choose(x: T, y: T): T { - return Math.random() < 0.5 ? x : y; +function choose(x: T, y: T): T { + return Math.random() < 0.5 ? x : y; } -var x = choose(10, 20); // Ok, x of type number +var x = choose(10, 20); // Ok, x of type number var y = choose("Five", 5); // Error ``` @@ -2999,13 +2998,13 @@ In the second call to 'choose', an inference is made from type 'string' to 'T' f In the example ```TypeScript -function map(a: T[], f: (x: T) => U): U[] { - var result: U[] = []; - for (var i = 0; i < a.length; i++) result.push(f(a[i])); - return result; +function map(a: T[], f: (x: T) => U): U[] { + var result: U[] = []; + for (var i = 0; i < a.length; i++) result.push(f(a[i])); + return result; } -var names = ["Peter", "Paul", "Mary"]; +var names = ["Peter", "Paul", "Mary"]; var lengths = map(names, s => s.length); ``` @@ -3020,22 +3019,22 @@ and the resulting type of 'lengths' is therefore 'number[]'. In the example ```TypeScript -function zip(x: S[], y: T[], combine: (x: S) => (y: T) => U): U[] { - var len = Math.max(x.length, y.length); - var result: U[] = []; - for (var i = 0; i < len; i++) result.push(combine(x[i])(y[i])); - return result; +function zip(x: S[], y: T[], combine: (x: S) => (y: T) => U): U[] { + var len = Math.max(x.length, y.length); + var result: U[] = []; + for (var i = 0; i < len; i++) result.push(combine(x[i])(y[i])); + return result; } -var names = ["Peter", "Paul", "Mary"]; -var ages = [7, 9, 12]; +var names = ["Peter", "Paul", "Mary"]; +var ages = [7, 9, 12]; var pairs = zip(names, ages, s => n => ({ name: s, age: n })); ``` inferences for 'S', 'T' and 'U' in the call to 'zip' are made as follows: Using the first two parameters, inferences of 'string' for 'S' and 'number' for 'T' are made. For the third parameter, inferential typing of the outer arrow expression causes 'S' to become fixed such that the inferred type 'string' can be used for the parameter 's'. When a function expression is inferentially typed, its return expression(s) are also inferentially typed. Thus, the inner arrow function is inferentially typed, causing 'T' to become fixed such that the inferred type 'number' can be used for the parameter 'n'. The return type of the inner arrow function can then be determined, which in turn determines the return type of the function returned from the outer arrow function, and inferences are made from the type '(s: string) => (n: number) => { name: string; age: number }' to the type '(x: S) => (y: T) => R', inferring '{ name: string; age: number }' for 'R'. Thus the call to 'zip' is equivalent to ```TypeScript -var pairs = zip( +var pairs = zip( names, ages, s => n => ({ name: s, age: n })); ``` @@ -3056,7 +3055,7 @@ The grammar ambiguity is resolved as follows: In a context where one possible in This rule means that the call to 'f' above is interpreted as a call with one argument, which is a call to a generic function 'g' with two type arguments and one regular argument. However, the statements ```TypeScript -f(g < A, B > 7); +f(g < A, B > 7); f(g < A, B > +(7)); ``` @@ -3066,8 +3065,8 @@ are both interpreted as calls to 'f' with two arguments. TypeScript extends the JavaScript expression grammar with the ability to assert a type for an expression: -  *UnaryExpression:* *( Modified )* -   … +  *UnaryExpression:* *( Modified )* +   …    `<` *Type* `>` *UnaryExpression* A type assertion expression consists of a type enclosed in `<` and `>` followed by a unary expression. Type assertion expressions are purely a compile-time construct. Type assertions are *not* checked at run-time and have no impact on the emitted JavaScript (and therefore no run-time cost). The type and the enclosing `<` and `>` are simply removed from the generated code. @@ -3081,9 +3080,9 @@ class Shape { ... } class Circle extends Shape { ... } -function createShape(kind: string): Shape { - if (kind === "circle") return new Circle(); - ... +function createShape(kind: string): Shape { + if (kind === "circle") return new Circle(); + ... } var circle = createShape("circle"); @@ -3094,10 +3093,10 @@ the type annotations indicate that the 'createShape' function *might* return a ' As mentioned above, type assertions are not checked at run-time and it is up to the programmer to guard against errors, for example using the `instanceof` operator: ```TypeScript -var shape = createShape(shapeKind); -if (shape instanceof Circle) { - var circle = shape; - ... +var shape = createShape(shapeKind); +if (shape instanceof Circle) { + var circle = shape; + ... } ``` @@ -3156,8 +3155,8 @@ The 'void' operator takes an operand of any type and produces the value 'undefin The 'typeof' operator takes an operand of any type and produces a value of the String primitive type. In positions where a type is expected, 'typeof' can also be used in a type query (section [3.8.10](#3.8.10)) to produce the type of an expression. ```TypeScript -var x = 5; -var y = typeof x; // Use in an expression +var x = 5; +var y = typeof x; // Use in an expression var z: typeof x; // Use in a type query ``` @@ -3241,7 +3240,7 @@ The && operator permits the operands to be of any type and produces a result of The || operator permits the operands to be of any type. -If the || expression is contextually typed (section [4.23](#4.23)), the operands are contextually typed by the same type. Otherwise, the left operand is not contextually typed and the right operand is contextually typed by the type of the left operand. +If the || expression is contextually typed (section [4.23](#4.23)), the operands are contextually typed by the same type. Otherwise, the left operand is not contextually typed and the right operand is contextually typed by the type of the left operand. The type of the result is the union type of the two operand types. @@ -3302,7 +3301,7 @@ In a destructuring assignment expression, the type of the expression on the righ * *S* is the type Any, or * *S* has an apparent property with the property name specified in *P* of a type that is assignable to the target given in *P*, or * *P* specifies a numeric property name and *S* has a numeric index signature of a type that is assignable to the target given in *P*, or - * *S* has a string index signature of a type that is assignable to the target given in *P*. + * *S* has a string index signature of a type that is assignable to the target given in *P*. * *V* is an array assignment pattern, *S* is the type Any or an array-like type (section [3.3.2](#3.3.2)), and, for each assignment element *E* in *V*, * *S* is the type Any, or * *S* is a tuple-like type (section [3.3.3](#3.3.3)) with a property named *N* of a type that is assignable to the target given in *E*, where *N* is the numeric index of *E* in the array assignment pattern, or @@ -3315,17 +3314,17 @@ In an assignment property or element that includes a default value, the type of When the output target is ECMAScript 2015 or higher, destructuring variable assignments remain unchanged in the emitted JavaScript code. When the output target is ECMAScript 3 or 5, destructuring variable assignments are rewritten to series of simple assignments. For example, the destructuring assignment ```TypeScript -var x = 1; -var y = 2; +var x = 1; +var y = 2; [x, y] = [y, x]; ``` is rewritten to the simple variable assignments ```TypeScript -var x = 1; -var y = 2; -_a = [y, x], x = _a[0], y = _a[1]; +var x = 1; +var y = 2; +_a = [y, x], x = _a[0], y = _a[1]; var _a; ``` @@ -3349,13 +3348,13 @@ Type checking of an expression is improved in several contexts by factoring in t * In a contextually typed object literal, each property value expression is contextually typed by * the type of the property with a matching name in the contextual type, if any, or otherwise * for a numerically named property, the numeric index type of the contextual type, if any, or otherwise - * the string index type of the contextual type, if any. + * the string index type of the contextual type, if any. * In a contextually typed array literal expression containing no spread elements, an element expression at index *N* is contextually typed by * the type of the property with the numeric name *N* in the contextual type, if any, or otherwise * the numeric index type of the contextual type, if any. * In a contextually typed array literal expression containing one or more spread elements, an element expression at index *N* is contextually typed by the numeric index type of the contextual type, if any. * In a contextually typed parenthesized expression, the contained expression is contextually typed by the same type. -* In a type assertion, the expression is contextually typed by the indicated type. +* In a type assertion, the expression is contextually typed by the indicated type. * In a || operator expression, if the expression is contextually typed, the operands are contextually typed by the same type. Otherwise, the right expression is contextually typed by the type of the left expression. * In a contextually typed conditional operator expression, the operands are contextually typed by the same type. * In an assignment expression, the right hand expression is contextually typed by the type of the left hand expression. @@ -3363,22 +3362,22 @@ Type checking of an expression is improved in several contexts by factoring in t In the following example ```TypeScript -interface EventObject { - x: number; - y: number; +interface EventObject { + x: number; + y: number; } -interface EventHandlers { - mousedown?: (event: EventObject) => void; - mouseup?: (event: EventObject) => void; - mousemove?: (event: EventObject) => void; +interface EventHandlers { + mousedown?: (event: EventObject) => void; + mouseup?: (event: EventObject) => void; + mousemove?: (event: EventObject) => void; } function setEventHandlers(handlers: EventHandlers) { ... } -setEventHandlers({ - mousedown: e => { startTracking(e.x, e.y); }, - mouseup: e => { endTracking(); } +setEventHandlers({ + mousedown: e => { startTracking(e.x, e.y); }, + mouseup: e => { endTracking(); } }); ``` @@ -3389,13 +3388,13 @@ the object literal passed to 'setEventHandlers' is contextually typed to the 'Ev Type guards are particular expression patterns involving the 'typeof' and 'instanceof' operators that cause the types of variables or parameters to be ***narrowed*** to more specific types. For example, in the code below, knowledge of the static type of 'x' in combination with a 'typeof' check makes it safe to narrow the type of 'x' to string in the first branch of the 'if' statement and number in the second branch of the 'if' statement. ```TypeScript -function foo(x: number | string) { - if (typeof x === "string") { - return x.length; // x has type string here - } - else { - return x + 1; // x has type number here - } +function foo(x: number | string) { + if (typeof x === "string") { + return x.length; // x has type string here + } + else { + return x + 1; // x has type number here + } } ``` @@ -3442,8 +3441,8 @@ Note that type guards affect types of variables and parameters only and have no In the example ```TypeScript -function isLongString(obj: any) { - return typeof obj === "string" && obj.length > 100; +function isLongString(obj: any) { + return typeof obj === "string" && obj.length > 100; } ``` @@ -3452,9 +3451,9 @@ the `obj` parameter has type `string` in the right operand of the && operator. In the example ```TypeScript -function processValue(value: number | (() => number)) { - var x = typeof value !== "number" ? value() : value; - // Process number in x +function processValue(value: number | (() => number)) { + var x = typeof value !== "number" ? value() : value; + // Process number in x } ``` @@ -3463,13 +3462,13 @@ the value parameter has type `() => number` in the first conditional expression In the example ```TypeScript -function f(x: string | number | boolean) { - if (typeof x === "string" || typeof x === "number") { - var y = x; // Type of y is string | number - } - else { - var z = x; // Type of z is boolean - } +function f(x: string | number | boolean) { + if (typeof x === "string" || typeof x === "number") { + var y = x; // Type of y is string | number + } + else { + var z = x; // Type of z is boolean + } } ``` @@ -3478,12 +3477,12 @@ the type of x is `string | number | boolean` in the left operand of the || opera In the example ```TypeScript -class C { - data: string | string[]; - getData() { - var data = this.data; - return typeof data === "string" ? data : data.join(" "); - } +class C { + data: string | string[]; + getData() { + var data = this.data; + return typeof data === "string" ? data : data.join(" "); + } } ``` @@ -3492,12 +3491,12 @@ the type of the `data` variable is `string` in the first conditional expression In the example ```TypeScript -class NamedItem { - name: string; +class NamedItem { + name: string; } -function getName(obj: Object) { - return obj instanceof NamedItem ? obj.name : "unknown"; +function getName(obj: Object) { + return obj instanceof NamedItem ? obj.name : "unknown"; } ``` @@ -3513,10 +3512,10 @@ This chapter describes the static type checking TypeScript provides for JavaScri Blocks are extended to include local interface, type alias, and enum declarations (classes are already included by the ECMAScript 2015 grammar). -  *Declaration:* *( Modified )* -   … -   *InterfaceDeclaration* -   *TypeAliasDeclaration* +  *Declaration:* *( Modified )* +   … +   *InterfaceDeclaration* +   *TypeAliasDeclaration*    *EnumDeclaration* Local class, interface, type alias, and enum declarations are block scoped, similar to let and const declarations. @@ -3525,8 +3524,8 @@ Local class, interface, type alias, and enum declarations are block scoped, simi Variable statements are extended to include optional type annotations. -  *VariableDeclaration:* *( Modified )* -   *SimpleVariableDeclaration* +  *VariableDeclaration:* *( Modified )* +   *SimpleVariableDeclaration*    *DestructuringVariableDeclaration* A variable declaration is either a simple variable declaration or a destructuring variable declaration. @@ -3535,7 +3534,7 @@ A variable declaration is either a simple variable declaration or a destructurin A ***simple variable declaration*** introduces a single named variable and optionally assigns it an initial value. -  *SimpleVariableDeclaration:* +  *SimpleVariableDeclaration:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* The type *T* of a variable introduced by a simple variable declaration is determined as follows: @@ -3553,20 +3552,20 @@ When a variable declaration has a type annotation, it is an error for that type Below are some examples of simple variable declarations and their associated types. ```TypeScript -var a; // any -var b: number; // number -var c = 1; // number -var d = { x: 1, y: "hello" }; // { x: number; y: string; } +var a; // any +var b: number; // number +var c = 1; // number +var d = { x: 1, y: "hello" }; // { x: number; y: string; } var e: any = "test"; // any ``` The following is permitted because all declarations of the single variable 'x' associate the same type (Number) with 'x'. ```TypeScript -var x = 1; -var x: number; -if (x == 1) { - var x = 2; +var x = 1; +var x: number; +if (x == 1) { + var x = 2; } ``` @@ -3575,10 +3574,10 @@ In the following example, all five variables are of the same type, '{ x: number; ```TypeScript interface Point { x: number; y: number; } -var a = { x: 0, y: undefined }; -var b: Point = { x: 0, y: undefined }; -var c = { x: 0, y: undefined }; -var d: { x: number; y: number; } = { x: 0, y: undefined }; +var a = { x: 0, y: undefined }; +var b: Point = { x: 0, y: undefined }; +var c = { x: 0, y: undefined }; +var d: { x: number; y: number; } = { x: 0, y: undefined }; var e = <{ x: number; y: number; }> { x: 0, y: undefined }; ``` @@ -3586,7 +3585,7 @@ var e = <{ x: number; y: number; }> { x: 0, y: undefined }; A ***destructuring variable declaration*** introduces zero or more named variables and initializes them with values extracted from properties of an object or elements of an array. -  *DestructuringVariableDeclaration:* +  *DestructuringVariableDeclaration:*    *BindingPattern* *TypeAnnotationopt* *Initializer* Each binding property or element that specifies an identifier introduces a variable by that name. The type of the variable is the widened form (section [3.12](#3.12)) of the type associated with the binding property or element, as defined in the following. @@ -3641,10 +3640,10 @@ var { x, p: y, q: z = false } = getSomeObject(); is rewritten to the simple variable declarations ```TypeScript -var _a = getSomeObject(), - x = _a.x, - y = _a.p, - _b = _a.q, +var _a = getSomeObject(), + x = _a.x, + y = _a.p, + _b = _a.q, z = _b === void 0 ? false : _b; ``` @@ -3659,10 +3658,10 @@ var [x, y, z = 10] = getSomeArray(); is rewritten to the simple variable declarations ```TypeScript -var _a = getSomeArray(), - x = _a[0], - y = _a[1], - _b = _a[2], +var _a = getSomeArray(), + x = _a[0], + y = _a[1], + _b = _a[2], z = _b === void 0 ? 10 : _b; ``` @@ -3675,12 +3674,12 @@ var { x, p: [y, z = 10] = getSomeArray() } = getSomeObject(); is rewritten to ```TypeScript -var _a = getSomeObject(), - x = _a.x, - _b = _a.p, - _c = _b === void 0 ? getSomeArray() : _b, - y = _c[0], - _d = _c[1], +var _a = getSomeObject(), + x = _a.x, + _b = _a.p, + _c = _b === void 0 ? getSomeArray() : _b, + y = _c[0], + _d = _c[1], z = _d === void 0 ? 10 : _d; ``` @@ -3718,14 +3717,14 @@ the array literal initializer expression is contextually typed by the implied ty Let and const declarations are exended to include optional type annotations. -  *LexicalBinding:* *( Modified )* -   *SimpleLexicalBinding* +  *LexicalBinding:* *( Modified )* +   *SimpleLexicalBinding*    *DestructuringLexicalBinding* -  *SimpleLexicalBinding:* +  *SimpleLexicalBinding:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* -  *DestructuringLexicalBinding:* +  *DestructuringLexicalBinding:*    *BindingPattern* *TypeAnnotationopt* *Initializeropt* *TODO: Document scoping and types of [let and const declarations](https://github.com/Microsoft/TypeScript/pull/904)*. @@ -3781,8 +3780,8 @@ In a function implementation without a return type annotation, the return type i In the example ```TypeScript -function f(): (x: string) => number { - return s => s.length; +function f(): (x: string) => number { + return s => s.length; } ``` @@ -3814,8 +3813,8 @@ TypeScript extends JavaScript functions to include type parameters, parameter an Function declarations are extended to permit the function body to be omitted in overload declarations. -  *FunctionDeclaration:* *( Modified )* -   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` +  *FunctionDeclaration:* *( Modified )* +   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}`    `function` *BindingIdentifieropt* *CallSignature* `;` A *FunctionDeclaration* introduces a named value of a function type in the containing declaration space. The *BindingIdentifier* is optional only when the function declaration occurs in an export default declaration (section [11.3.4.2](#11.3.4.2)). @@ -3837,26 +3836,26 @@ The parameter list of a function overload cannot specify default values for para The following is an example of a function with overloads. ```TypeScript -function attr(name: string): string; -function attr(name: string, value: string): Accessor; -function attr(map: any): Accessor; -function attr(nameOrMap: any, value?: string): any { - if (nameOrMap && typeof nameOrMap === "string") { - // handle string case - } - else { - // handle map case - } +function attr(name: string): string; +function attr(name: string, value: string): Accessor; +function attr(map: any): Accessor; +function attr(nameOrMap: any, value?: string): any { + if (nameOrMap && typeof nameOrMap === "string") { + // handle string case + } + else { + // handle map case + } } ``` Note that each overload and the final implementation specify the same identifier. The type of the local variable 'attr' introduced by this declaration is ```TypeScript -var attr: { - (name: string): string; - (name: string, value: string): Accessor; - (map: any): Accessor; +var attr: { + (name: string): string; + (name: string, value: string): Accessor; + (map: any): Accessor; }; ``` @@ -3874,13 +3873,13 @@ A function implementation without a return type annotation is said to be an ***i In the example ```TypeScript -function f(x: number) { - if (x <= 0) return x; - return g(x); +function f(x: number) { + if (x <= 0) return x; + return g(x); } -function g(x: number) { - return f(x - 1); +function g(x: number) { + return f(x - 1); } ``` @@ -3897,27 +3896,27 @@ Initializer expressions are evaluated in the scope of the function body but are When the output target is ECMAScript 3 or 5, for each parameter with an initializer, a statement that substitutes the default value for an omitted argument is included in the generated JavaScript, as described in section [6.6](#6.6). The example ```TypeScript -function strange(x: number, y = x * 2, z = x + y) { - return z; +function strange(x: number, y = x * 2, z = x + y) { + return z; } ``` generates JavaScript that is equivalent to ```TypeScript -function strange(x, y, z) { - if (y === void 0) { y = x * 2; } - if (z === void 0) { z = x + y; } - return z; +function strange(x, y, z) { + if (y === void 0) { y = x * 2; } + if (z === void 0) { z = x + y; } + return z; } ``` In the example ```TypeScript -var x = 1; -function f(a = x) { - var x = "hello"; +var x = 1; +function f(a = x) { + var x = "hello"; } ``` @@ -3941,8 +3940,8 @@ When the output target is ECMAScript 2015 or higher, except for removing the opt The example ```TypeScript -function drawText({ text = "", location: [x, y] = [0, 0], bold = false }) { - // Draw text +function drawText({ text = "", location: [x, y] = [0, 0], bold = false }) { + // Draw text } ``` @@ -3955,30 +3954,30 @@ declares a function `drawText` that takes a single parameter of the type When the output target is ECMAScript 3 or 5, the function is rewritten to ```TypeScript -function drawText(_a) { - var _b = _a.text, - text = _b === void 0 ? "" : _b, - _c = _a.location, - _d = _c === void 0 ? [0, 0] : _c, - x = _d[0], - y = _d[1], - _e = _a.bold, - bold = _e === void 0 ? false : _e; - // Draw text +function drawText(_a) { + var _b = _a.text, + text = _b === void 0 ? "" : _b, + _c = _a.location, + _d = _c === void 0 ? [0, 0] : _c, + x = _d[0], + y = _d[1], + _e = _a.bold, + bold = _e === void 0 ? false : _e; + // Draw text } ``` Destructuring parameter declarations do not permit type annotations on the individual binding patterns, as such annotations would conflict with the already established meaning of colons in object literals. Type annotations must instead be written on the top-level parameter declaration. For example ```TypeScript -interface DrawTextInfo { - text?: string; - location?: [number, number]; - bold?: boolean; +interface DrawTextInfo { + text?: string; + location?: [number, number]; + bold?: boolean; } -function drawText({ text, location: [x, y], bold }: DrawTextInfo) { - // Draw text +function drawText({ text, location: [x, y], bold }: DrawTextInfo) { + // Draw text } ``` @@ -3991,14 +3990,14 @@ Type parameters declared in the signature of a function implementation are in sc The following is an example of a generic function: ```TypeScript -interface Comparable { - localeCompare(other: any): number; +interface Comparable { + localeCompare(other: any): number; } -function compare(x: T, y: T): number { - if (x == null) return y == null ? 0 : -1; - if (y == null) return 1; - return x.localeCompare(y); +function compare(x: T, y: T): number { + if (x == null) return y == null ? 0 : -1; + if (y == null) return 1; + return x.localeCompare(y); } ``` @@ -4007,11 +4006,11 @@ Note that the 'x' and 'y' parameters are known to be subtypes of the constraint The type arguments of a call to a generic function may be explicitly specified in a call operation or may, when possible, be inferred (section [4.15.2](#4.15.2)) from the types of the regular arguments in the call. In the example ```TypeScript -class Person { - name: string; - localeCompare(other: Person) { - return compare(this.name, other.name); - } +class Person { + name: string; + localeCompare(other: Person) { + return compare(this.name, other.name); + } } ``` @@ -4022,9 +4021,9 @@ the type argument to 'compare' is automatically inferred to be the String type b A function declaration generates JavaScript code that is equivalent to: ```TypeScript -function () { - - +function () { + + } ``` @@ -4070,17 +4069,17 @@ Class declarations may reference interfaces in their implements clause to valida An interface declaration declares an ***interface type***. -  *InterfaceDeclaration:* +  *InterfaceDeclaration:*    `interface` *BindingIdentifier* *TypeParametersopt* *InterfaceExtendsClauseopt* *ObjectType* -  *InterfaceExtendsClause:* +  *InterfaceExtendsClause:*    `extends` *ClassOrInterfaceTypeList* -  *ClassOrInterfaceTypeList:* -   *ClassOrInterfaceType* +  *ClassOrInterfaceTypeList:* +   *ClassOrInterfaceType*    *ClassOrInterfaceTypeList* `,` *ClassOrInterfaceType* -  *ClassOrInterfaceType:* +  *ClassOrInterfaceType:*    *TypeReference* An *InterfaceDeclaration* introduces a named type (section [3.7](#3.7)) in the containing declaration space. The *BindingIdentifier* of an interface declaration may not be one of the predefined type names (section [3.8.1](#3.8.1)). @@ -4108,22 +4107,22 @@ An interface is permitted to inherit identical members from multiple base types Below is an example of two interfaces that contain properties with the same name but different types: ```TypeScript -interface Mover { - move(): void; - getStatus(): { speed: number; }; +interface Mover { + move(): void; + getStatus(): { speed: number; }; } -interface Shaker { - shake(): void; - getStatus(): { frequency: number; }; +interface Shaker { + shake(): void; + getStatus(): { frequency: number; }; } ``` An interface that extends 'Mover' and 'Shaker' must declare a new 'getStatus' property as it would otherwise inherit two 'getStatus' properties with different types. The new 'getStatus' property must be declared such that the resulting 'MoverShaker' is a subtype of both 'Mover' and 'Shaker': ```TypeScript -interface MoverShaker extends Mover, Shaker { - getStatus(): { speed: number; frequency: number; }; +interface MoverShaker extends Mover, Shaker { + getStatus(): { speed: number; frequency: number; }; } ``` @@ -4146,30 +4145,30 @@ In an interface with multiple declarations, the `extends` clauses are merged int For example, a sequence of declarations in this order: ```TypeScript -interface Document { - createElement(tagName: any): Element; +interface Document { + createElement(tagName: any): Element; } -interface Document { - createElement(tagName: string): HTMLElement; +interface Document { + createElement(tagName: string): HTMLElement; } -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; +interface Document { + createElement(tagName: "div"): HTMLDivElement; + createElement(tagName: "span"): HTMLSpanElement; + createElement(tagName: "canvas"): HTMLCanvasElement; } ``` is equivalent to the following single declaration: ```TypeScript -interface Document { - createElement(tagName: "div"): HTMLDivElement; - createElement(tagName: "span"): HTMLSpanElement; - createElement(tagName: "canvas"): HTMLCanvasElement; - createElement(tagName: string): HTMLElement; - createElement(tagName: any): Element; +interface Document { + createElement(tagName: "div"): HTMLDivElement; + createElement(tagName: "span"): HTMLSpanElement; + createElement(tagName: "canvas"): HTMLCanvasElement; + createElement(tagName: string): HTMLElement; + createElement(tagName: any): Element; } ``` @@ -4182,27 +4181,27 @@ Note that the members of the last interface declaration appear first in the merg When an interface type extends a class type it inherits the members of the class but not their implementations. It is as if the interface had declared all of the members of the class without providing an implementation. Interfaces inherit even the private and protected members of a base class. When a class containing private or protected members is the base type of an interface type, that interface type can only be implemented by that class or a descendant class. For example: ```TypeScript -class Control { - private state: any; +class Control { + private state: any; } -interface SelectableControl extends Control { - select(): void; +interface SelectableControl extends Control { + select(): void; } -class Button extends Control { - select() { } +class Button extends Control { + select() { } } -class TextBox extends Control { - select() { } +class TextBox extends Control { + select() { } } -class Image extends Control { +class Image extends Control { } -class Location { - select() { } +class Location { + select() { } } ``` @@ -4215,18 +4214,18 @@ Within the 'Control' class it is possible to access the 'state' private member t TypeScript does not provide a direct mechanism for dynamically testing whether an object implements a particular interface. Instead, TypeScript code can use the JavaScript technique of checking whether an appropriate set of members are present on the object. For example, given the declarations in section [7.1](#7.1), the following is a dynamic check for the 'MoverShaker' interface: ```TypeScript -var obj: any = getSomeObject(); -if (obj && obj.move && obj.shake && obj.getStatus) { - var moverShaker = obj; - ... +var obj: any = getSomeObject(); +if (obj && obj.move && obj.shake && obj.getStatus) { + var moverShaker = obj; + ... } ``` If such a check is used often it can be abstracted into a function: ```TypeScript -function asMoverShaker(obj: any): MoverShaker { - return obj && obj.move && obj.shake && obj.getStatus ? obj : null; +function asMoverShaker(obj: any): MoverShaker { + return obj && obj.move && obj.shake && obj.getStatus ? obj : null; } ``` @@ -4242,7 +4241,7 @@ TypeScript extends JavaScript classes to include type parameters, implements cla A class declaration declares a ***class type*** and a ***constructor function***. -  *ClassDeclaration:* *( Modified )* +  *ClassDeclaration:* *( Modified )*    `class` *BindingIdentifieropt* *TypeParametersopt* *ClassHeritage* `{` *ClassBody* `}` A *ClassDeclaration* introduces a named type (the class type) and a named value (the constructor function) in the containing declaration space. The class type is formed from the instance members declared in the class body and the instance members inherited from the base class. The constructor function is given an anonymous type formed from the constructor declaration, the static member declarations in the class body, and the static members inherited from the base class. The constructor function initializes and returns an instance of the class type. @@ -4254,29 +4253,29 @@ A class may optionally have type parameters (section [3.6.1](#3.6.1)) that serve The following example introduces both a named type called 'Point' (the class type) and a named value called 'Point' (the constructor function) in the containing declaration space. ```TypeScript -class Point { - constructor(public x: number, public y: number) { } - public length() { return Math.sqrt(this.x * this.x + this.y * this.y); } - static origin = new Point(0, 0); +class Point { + constructor(public x: number, public y: number) { } + public length() { return Math.sqrt(this.x * this.x + this.y * this.y); } + static origin = new Point(0, 0); } ``` The named type 'Point' is exactly equivalent to ```TypeScript -interface Point { - x: number; - y: number; - length(): number; +interface Point { + x: number; + y: number; + length(): number; } ``` The named value 'Point' is a constructor function whose type corresponds to the declaration ```TypeScript -var Point: { - new(x: number, y: number): Point; - origin: Point; +var Point: { + new(x: number, y: number): Point; + origin: Point; }; ``` @@ -4294,16 +4293,16 @@ the identifier 'Point' in the type annotation refers to the class type, whereas The heritage specification of a class consists of optional `extends` and `implements` clauses. The `extends` clause specifies the base class of the class and the `implements` clause specifies a set of interfaces for which to validate the class provides an implementation. -  *ClassHeritage:* *( Modified )* +  *ClassHeritage:* *( Modified )*    *ClassExtendsClauseopt* *ImplementsClauseopt* -  *ClassExtendsClause:* +  *ClassExtendsClause:*    `extends`  *ClassType* -  *ClassType:* +  *ClassType:*    *TypeReference* -  *ImplementsClause:* +  *ImplementsClause:*    `implements` *ClassOrInterfaceTypeList* A class that includes an `extends` clause is called a ***derived class***, and the class specified in the `extends` clause is called the ***base class*** of the derived class. When a class heritage specification omits the `extends` clause, the class does not have a base class. However, as is the case with every object type, type references (section [3.3.1](#3.3.1)) to the class will appear to have the members of the global interface type named 'Object' unless those members are hidden by members with the same name in the class. @@ -4320,9 +4319,9 @@ The following example illustrates a situation in which the first rule above woul ```TypeScript class A { a: number; } -namespace Foo { - var A = 1; - class B extends A { b: string; } +namespace Foo { + var A = 1; + class B extends A { b: string; } } ``` @@ -4336,9 +4335,9 @@ Note that because TypeScript has a structural type system, a class doesn't need The class body consists of zero or more constructor or member declarations. Statements are not allowed in the body of a class—they must be placed in the constructor or in members. -  *ClassElement:* *( Modified )* -   *ConstructorDeclaration* -   *PropertyMemberDeclaration* +  *ClassElement:* *( Modified )* +   *ConstructorDeclaration* +   *PropertyMemberDeclaration*    *IndexMemberDeclaration* The body of class may optionally contain a single constructor declaration. Constructor declarations are described in section [8.3](#8.3). @@ -4374,24 +4373,24 @@ Private and protected accessibility is enforced only at compile-time and serves The following example demonstrates private and protected accessibility: ```TypeScript -class A { - private x: number; - protected y: number; - static f(a: A, b: B) { - a.x = 1; // Ok - b.x = 1; // Ok - a.y = 1; // Ok - b.y = 1; // Ok - } +class A { + private x: number; + protected y: number; + static f(a: A, b: B) { + a.x = 1; // Ok + b.x = 1; // Ok + a.y = 1; // Ok + b.y = 1; // Ok + } } -class B extends A { - static f(a: A, b: B) { - a.x = 1; // Error, x only accessible within A - b.x = 1; // Error, x only accessible within A - a.y = 1; // Error, y must be accessed through instance of B - b.y = 1; // Ok - } +class B extends A { + static f(a: A, b: B) { + a.x = 1; // Error, x only accessible within A + b.x = 1; // Error, x only accessible within A + a.y = 1; // Error, y must be accessed through instance of B + b.y = 1; // Ok + } } ``` @@ -4427,37 +4426,37 @@ All instance property members (including those that are private or protected) of In the example ```TypeScript -class A { - public x: number; - public f() { } - public g(a: any) { return undefined; } - static s: string; +class A { + public x: number; + public f() { } + public g(a: any) { return undefined; } + static s: string; } -class B extends A { - public y: number; - public g(b: boolean) { return false; } +class B extends A { + public y: number; + public g(b: boolean) { return false; } } ``` the class type of 'A' is equivalent to ```TypeScript -interface A { - x: number; - f: () => void; - g: (a: any) => any; +interface A { + x: number; + f: () => void; + g: (a: any) => any; } ``` and the class type of 'B' is equivalent to ```TypeScript -interface B { - x: number; - y: number; - f: () => void; - g: (b: boolean) => boolean; +interface B { + x: number; + y: number; + f: () => void; + g: (b: boolean) => boolean; } ``` @@ -4482,8 +4481,8 @@ Every class automatically contains a static property member named 'prototype', t The example ```TypeScript -class Pair { - constructor(public item1: T1, public item2: T2) { } +class Pair { + constructor(public item1: T1, public item2: T2) { } } class TwoArrays extends Pair { } @@ -4492,26 +4491,26 @@ class TwoArrays extends Pair { } introduces two named types corresponding to ```TypeScript -interface Pair { - item1: T1; - item2: T2; +interface Pair { + item1: T1; + item2: T2; } -interface TwoArrays { - item1: T[]; - item2: T[]; +interface TwoArrays { + item1: T[]; + item2: T[]; } ``` and two constructor functions corresponding to ```TypeScript -var Pair: { - new (item1: T1, item2: T2): Pair; +var Pair: { + new (item1: T1, item2: T2): Pair; } -var TwoArrays: { - new (item1: T[], item2: T[]): TwoArrays; +var TwoArrays: { + new (item1: T[], item2: T[]): TwoArrays; } ``` @@ -4521,8 +4520,8 @@ Note that each construct signature in the constructor function types has the sam A constructor declaration declares the constructor function of a class. -  *ConstructorDeclaration:* -   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}` +  *ConstructorDeclaration:* +   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}`    *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `;` Constructor declarations that specify a body are called ***constructor implementations*** and constructor declarations without a body are called ***constructor overloads***. It is possible to specify multiple constructor overloads in a class, but a class can have at most one constructor implementation. All constructor declarations in a class must specify the same set of modifiers. Only public constructors are supported and private or protected constructors result in an error. @@ -4544,24 +4543,24 @@ Similar to functions, only the constructor implementation (and not constructor o A parameter of a *ConstructorImplementation* may be prefixed with a `public`, `private`, or `protected` modifier. This is called a ***parameter property declaration*** and is shorthand for declaring a property with the same name as the parameter and initializing it with the value of the parameter. For example, the declaration ```TypeScript -class Point { - constructor(public x: number, public y: number) { - // Constructor body - } +class Point { + constructor(public x: number, public y: number) { + // Constructor body + } } ``` is equivalent to writing ```TypeScript -class Point { - public x: number; - public y: number; - constructor(x: number, y: number) { - this.x = x; - this.y = y; - // Constructor body - } +class Point { + public x: number; + public y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + // Constructor body + } } ``` @@ -4572,10 +4571,10 @@ A parameter property declaration may declare an optional parameter (by including Super calls (section [4.9.1](#4.9.1)) are used to call the constructor of the base class. A super call consists of the keyword `super` followed by an argument list enclosed in parentheses. For example: ```TypeScript -class ColoredPoint extends Point { - constructor(x: number, y: number, public color: string) { - super(x, y); - } +class ColoredPoint extends Point { + constructor(x: number, y: number, public color: string) { + super(x, y); + } } ``` @@ -4608,9 +4607,9 @@ and then executes the instance member variable initializers, if any. Property member declarations can be member variable declarations, member function declarations, or member accessor declarations. -  *PropertyMemberDeclaration:* -   *MemberVariableDeclaration* -   *MemberFunctionDeclaration* +  *PropertyMemberDeclaration:* +   *MemberVariableDeclaration* +   *MemberFunctionDeclaration*    *MemberAccessorDeclaration* Member declarations without a `static` modifier are called instance member declarations. Instance property member declarations declare properties in the class type (section [8.2.4](#8.2.4)), and must specify names that are unique among all instance property member and parameter property declarations in the containing class, with the exception that instance get and set accessor declarations may pairwise specify the same name. @@ -4626,35 +4625,35 @@ Every class automatically contains a static property member named 'prototype', t Below is an example of a class containing both instance and static property member declarations: ```TypeScript -class Point { - constructor(public x: number, public y: number) { } - public distance(p: Point) { - var dx = this.x - p.x; - var dy = this.y - p.y; - return Math.sqrt(dx * dx + dy * dy); - } - static origin = new Point(0, 0); - static distance(p1: Point, p2: Point) { return p1.distance(p2); } +class Point { + constructor(public x: number, public y: number) { } + public distance(p: Point) { + var dx = this.x - p.x; + var dy = this.y - p.y; + return Math.sqrt(dx * dx + dy * dy); + } + static origin = new Point(0, 0); + static distance(p1: Point, p2: Point) { return p1.distance(p2); } } ``` The class type 'Point' has the members: ```TypeScript -interface Point { - x: number; - y: number; - distance(p: Point); +interface Point { + x: number; + y: number; + distance(p: Point); } ``` and the constructor function 'Point' has a type corresponding to the declaration: ```TypeScript -var Point: { - new(x: number, y: number): Point; - origin: Point; - distance(p1: Point, p2: Point): number; +var Point: { + new(x: number, y: number): Point; + origin: Point; + distance(p1: Point, p2: Point): number; } ``` @@ -4662,7 +4661,7 @@ var Point: { A member variable declaration declares an instance member variable or a static member variable. -  *MemberVariableDeclaration:* +  *MemberVariableDeclaration:*    *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* *Initializeropt* `;` The type associated with a member variable declaration is determined in the same manner as an ordinary variable declaration (see section [5.2](#5.2)). @@ -4676,29 +4675,29 @@ Initializer expressions for instance member variables are evaluated in the scope Since instance member variable initializers are equivalent to assignments to properties of `this` in the constructor, the example ```TypeScript -class Employee { - public name: string; - public address: string; - public retired = false; - public manager: Employee = null; - public reports: Employee[] = []; +class Employee { + public name: string; + public address: string; + public retired = false; + public manager: Employee = null; + public reports: Employee[] = []; } ``` is equivalent to ```TypeScript -class Employee { - public name: string; - public address: string; - public retired: boolean; - public manager: Employee; - public reports: Employee[]; - constructor() { - this.retired = false; - this.manager = null; - this.reports = []; - } +class Employee { + public name: string; + public address: string; + public retired: boolean; + public manager: Employee; + public reports: Employee[]; + constructor() { + this.retired = false; + this.manager = null; + this.reports = []; + } } ``` @@ -4706,8 +4705,8 @@ class Employee { A member function declaration declares an instance member function or a static member function. -  *MemberFunctionDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}` +  *MemberFunctionDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` A member function declaration is processed in the same manner as an ordinary function declaration (section [6](#6)), except that in a member function `this` has a known type. @@ -4721,48 +4720,48 @@ A static member function declaration declares a property in the constructor func A member function can access overridden base class members using a super property access (section [4.9.2](#4.9.2)). For example ```TypeScript -class Point { - constructor(public x: number, public y: number) { } - public toString() { - return "x=" + this.x + " y=" + this.y; - } +class Point { + constructor(public x: number, public y: number) { } + public toString() { + return "x=" + this.x + " y=" + this.y; + } } -class ColoredPoint extends Point { - constructor(x: number, y: number, public color: string) { - super(x, y); - } - public toString() { - return super.toString() + " color=" + this.color; - } +class ColoredPoint extends Point { + constructor(x: number, y: number, public color: string) { + super(x, y); + } + public toString() { + return super.toString() + " color=" + this.color; + } } ``` In a static member function, `this` represents the constructor function object on which the static member function was invoked. Thus, a call to 'new this()' may actually invoke a derived class constructor: ```TypeScript -class A { - a = 1; - static create() { - return new this(); - } +class A { + a = 1; + static create() { + return new this(); + } } -class B extends A { - b = 2; +class B extends A { + b = 2; } -var x = A.create(); // new A() +var x = A.create(); // new A() var y = B.create(); // new B() ``` Note that TypeScript doesn't require or verify that derived constructor functions are subtypes of base constructor functions. In other words, changing the declaration of 'B' to ```TypeScript -class B extends A { - constructor(public b: number) { - super(); - } +class B extends A { + constructor(public b: number) { + super(); + } } ``` @@ -4772,8 +4771,8 @@ does not cause errors in the example, even though the call to the constructor fr A member accessor declaration declares an instance member accessor or a static member accessor. -  *MemberAccessorDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *GetAccessor* +  *MemberAccessorDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *GetAccessor*    *AccessibilityModifieropt* `static`*opt* *SetAccessor* Get and set accessors are processed in the same manner as in an object literal (section [4.5](#4.5)), except that a contextual type is never available in a member accessor declaration. @@ -4798,7 +4797,7 @@ If the *PropertyName* of a property member declaration is a computed property na An index member declaration introduces an index signature (section [3.9.4](#3.9.4)) in the class type. -  *IndexMemberDeclaration:* +  *IndexMemberDeclaration:*    *IndexSignature* `;` Index member declarations have no body and cannot specify an accessibility modifier. @@ -4822,16 +4821,16 @@ When the output target is ECMAScript 2015 or higher, type parameters, implements A class with no `extends` clause generates JavaScript equivalent to the following: ```TypeScript -var = (function () { - function () { - - - - - } - - - return ; +var = (function () { + function () { + + + + + } + + + return ; })(); ``` @@ -4864,18 +4863,18 @@ where *MemberName* is the name of the member variable and *InitializerExpression An instance member function declaration generates a statement of the form ```TypeScript -.prototype. = function () { - - +.prototype. = function () { + + } ``` and static member function declaration generates a statement of the form ```TypeScript -. = function () { - - +. = function () { + + } ``` @@ -4884,30 +4883,30 @@ where *MemberName* is the name of the member function, and *FunctionParameters*, A get or set instance member accessor declaration, or a pair of get and set instance member accessor declarations with the same name, generates a statement of the form ```TypeScript -Object.defineProperty(.prototype, "", { - get: function () { - - }, - set: function () { - - }, - enumerable: true, - configurable: true +Object.defineProperty(.prototype, "", { + get: function () { + + }, + set: function () { + + }, + enumerable: true, + configurable: true }; ``` and a get or set static member accessor declaration, or a pair of get and set static member accessor declarations with the same name, generates a statement of the form ```TypeScript -Object.defineProperty(, "", { - get: function () { - - }, - set: function () { - - }, - enumerable: true, - configurable: true +Object.defineProperty(, "", { + get: function () { + + }, + set: function () { + + }, + enumerable: true, + configurable: true }; ``` @@ -4926,29 +4925,29 @@ where *MemberName* is the name of the static variable, and *InitializerExpressio A class with an `extends` clause generates JavaScript equivalent to the following: ```TypeScript -var = (function (_super) { - __extends(, _super); - function () { - - - - - - } - - - return ; +var = (function (_super) { + __extends(, _super); + function () { + + + + + + } + + + return ; })(); ``` In addition, the '__extends' function below is emitted at the beginning of the JavaScript source file. It copies all properties from the base constructor function object to the derived constructor function object (in order to inherit static members), and appropriately establishes the 'prototype' property of the derived constructor function object. ```TypeScript -var __extends = this.__extends || function(d, b) { - for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; - function f() { this.constructor = d; } - f.prototype = b.prototype; - d.prototype = new f(); +var __extends = this.__extends || function(d, b) { + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; + function f() { this.constructor = d; } + f.prototype = b.prototype; + d.prototype = new f(); } ``` @@ -5006,7 +5005,7 @@ An enum type is a distinct subtype of the Number primitive type with an associat An enum declaration declares an ***enum type*** and an ***enum object***. -  *EnumDeclaration:* +  *EnumDeclaration:*    `const`*opt* `enum` *BindingIdentifier* `{` *EnumBodyopt* `}` An *EnumDeclaration* introduces a named type (the enum type) and a named value (the enum object) in the containing declaration space. The enum type is a distinct subtype of the Number primitive type. The enum object is a value of an anonymous object type containing a set of properties, all of the enum type, corresponding to the values declared for the enum type in the body of the declaration. The enum object's type furthermore includes a numeric index signature with the signature '[x: number]: string'. @@ -5024,18 +5023,18 @@ enum Color { Red, Green, Blue } declares a subtype of the Number primitive type called 'Color' and introduces a variable 'Color' with a type that corresponds to the declaration ```TypeScript -var Color: { - [x: number]: string; - Red: Color; - Green: Color; - Blue: Color; +var Color: { + [x: number]: string; + Red: Color; + Green: Color; + Blue: Color; }; ``` The numeric index signature reflects a "reverse mapping" that is automatically generated in every enum object, as described in section [9.5](#9.5). The reverse mapping provides a convenient way to obtain the string representation of an enum value. For example ```TypeScript -var c = Color.Red; +var c = Color.Red; console.log(Color[c]); // Outputs "Red" ``` @@ -5043,18 +5042,18 @@ console.log(Color[c]); // Outputs "Red" The body of an enum declaration defines zero or more enum members which are the named values of the enum type. Each enum member has an associated numeric value of the primitive type introduced by the enum declaration. -  *EnumBody:* +  *EnumBody:*    *EnumMemberList* `,`*opt* -  *EnumMemberList:* -   *EnumMember* +  *EnumMemberList:* +   *EnumMember*    *EnumMemberList* `,` *EnumMember* -  *EnumMember:* -   *PropertyName* +  *EnumMember:* +   *PropertyName*    *PropertyName* = *EnumValue* -  *EnumValue:* +  *EnumValue:*    *AssignmentExpression* The *PropertyName* of an enum member cannot be a computed property name ([2.2.3](#2.2.3)). @@ -5080,12 +5079,12 @@ A ***constant enum expression*** is a subset of the expression grammar that can In the example ```TypeScript -enum Test { - A, - B, - C = Math.floor(Math.random() * 1000), - D = 10, - E +enum Test { + A, + B, + C = Math.floor(Math.random() * 1000), + D = 10, + E } ``` @@ -5094,13 +5093,13 @@ enum Test { In the example ```TypeScript -enum Style { - None = 0, - Bold = 1, - Italic = 2, - Underline = 4, - Emphasis = Bold | Italic, - Hyperlink = Bold | Underline +enum Style { + None = 0, + Bold = 1, + Italic = 2, + Underline = 4, + Emphasis = Bold | Italic, + Hyperlink = Bold | Underline } ``` @@ -5121,14 +5120,14 @@ An enum declaration that specifies a `const` modifier is a ***constant enum decl Unlike regular enum declarations, constant enum declarations are completely erased in the emitted JavaScript code. For this reason, it is an error to reference a constant enum object in any other context than a property access that selects one of the enum's members. For example: ```TypeScript -const enum Comparison { - LessThan = -1, - EqualTo = 0, - GreaterThan = 1 +const enum Comparison { + LessThan = -1, + EqualTo = 0, + GreaterThan = 1 } -var x = Comparison.EqualTo; // Ok, replaced with 0 in emitted code -var y = Comparison[Comparison.EqualTo]; // Error +var x = Comparison.EqualTo; // Ok, replaced with 0 in emitted code +var y = Comparison[Comparison.EqualTo]; // Error var z = Comparison; // Error ``` @@ -5139,9 +5138,9 @@ The entire const enum declaration is erased in the emitted JavaScript code. Thus An enum declaration generates JavaScript equivalent to the following: ```TypeScript -var ; -(function () { - +var ; +(function () { + })(||(={})); ``` @@ -5158,11 +5157,11 @@ where *MemberName* is the name of the enum member and *Value* is the assigned co For example, the 'Color' enum example from section [9.1](#9.1) generates the following JavaScript: ```TypeScript -var Color; -(function (Color) { - Color[Color["Red"] = 0] = "Red"; - Color[Color["Green"] = 1] = "Green"; - Color[Color["Blue"] = 2] = "Blue"; +var Color; +(function (Color) { + Color[Color["Red"] = 0] = "Red"; + Color[Color["Green"] = 1] = "Green"; + Color[Color["Blue"] = 2] = "Blue"; })(Color||(Color={})); ``` @@ -5176,11 +5175,11 @@ Namespaces provide a mechanism for organizing code and declarations in hierarchi A namespace declaration introduces a name with a namespace meaning and, in the case of an instantiated namespace, a value meaning in the containing declaration space. -  *NamespaceDeclaration:* +  *NamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *NamespaceBody* `}` -  *IdentifierPath:* -   *BindingIdentifier* +  *IdentifierPath:* +   *BindingIdentifier*    *IdentifierPath* `.` *BindingIdentifier* Namespaces are declared using the `namespace` keyword, but for backward compatibility of earlier versions of TypeScript a `module` keyword can also be used. @@ -5190,15 +5189,15 @@ Namespaces are either ***instantiated*** or ***non-instantiated***. A non-instan When a namespace identifier is referenced as a *NamespaceName* (section [3.8.2](#3.8.2)) it denotes a container of namespace and type names, and when a namespace identifier is referenced as a *PrimaryExpression* (section [4.3](#4.3)) it denotes the singleton namespace instance. For example: ```TypeScript -namespace M { - export interface P { x: number; y: number; } - export var a = 1; +namespace M { + export interface P { x: number; y: number; } + export var a = 1; } -var p: M.P; // M used as NamespaceName -var m = M; // M used as PrimaryExpression -var x1 = M.a; // M used as PrimaryExpression -var x2 = m.a; // Same as M.a +var p: M.P; // M used as NamespaceName +var m = M; // M used as PrimaryExpression +var x1 = M.a; // M used as PrimaryExpression +var x2 = m.a; // Same as M.a var q: m.P; // Error ``` @@ -5209,30 +5208,30 @@ If the declaration of 'M' above had excluded the exported variable 'a', 'M' woul A namespace declaration that specifies an *IdentifierPath* with more than one identifier is equivalent to a series of nested single-identifier namespace declarations where all but the outermost are automatically exported. For example: ```TypeScript -namespace A.B.C { - export var x = 1; +namespace A.B.C { + export var x = 1; } ``` corresponds to ```TypeScript -namespace A { - export namespace B { - export namespace C { - export var x = 1; - } - } +namespace A { + export namespace B { + export namespace C { + export var x = 1; + } + } } ``` The hierarchy formed by namespace and named type names partially mirrors that formed by namespace instances and members. The example ```TypeScript -namespace A { - export namespace B { - export class C { } - } +namespace A { + export namespace B { + export class C { } + } } ``` @@ -5248,49 +5247,49 @@ the two occurrences of 'A.B.C' in fact refer to different entities. It is the co The body of a namespace corresponds to a function that is executed once to initialize the namespace instance. -  *NamespaceBody:* +  *NamespaceBody:*    *NamespaceElementsopt* -  *NamespaceElements:* -   *NamespaceElement* +  *NamespaceElements:* +   *NamespaceElement*    *NamespaceElements* *NamespaceElement* -  *NamespaceElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration -   AmbientDeclaration -   ImportAliasDeclaration +  *NamespaceElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration +   AmbientDeclaration +   ImportAliasDeclaration    ExportNamespaceElement* -  *ExportNamespaceElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportNamespaceElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* ## 10.3 Import Alias Declarations Import alias declarations are used to create local aliases for entities in other namespaces. -  *ImportAliasDeclaration:* +  *ImportAliasDeclaration:*    `import` *BindingIdentifier* `=` *EntityName* `;` -  *EntityName:* -   *NamespaceName* +  *EntityName:* +   *NamespaceName*    *NamespaceName* `.` *IdentifierReference* An *EntityName* consisting of a single identifier is resolved as a *NamespaceName* and is thus required to reference a namespace. The resulting local alias references the given namespace and is itself classified as a namespace. @@ -5300,16 +5299,16 @@ An *EntityName* consisting of more than one identifier is resolved as a *Namespa In the example ```TypeScript -namespace A { - export interface X { s: string } - export var X: X; +namespace A { + export interface X { s: string } + export var X: X; } -namespace B { - interface A { n: number } - import Y = A; // Alias for namespace A - import Z = A.X; // Alias for type and value A.X - var v: Z = Z; +namespace B { + interface A { n: number } + import Y = A; // Alias for namespace A + import Z = A.X; // Alias for type and value A.X + var v: Z = Z; } ``` @@ -5318,13 +5317,13 @@ within 'B', 'Y' is an alias only for namespace 'A' and not the local interface ' If the *NamespaceName* portion of an *EntityName* references an instantiated namespace, the *NamespaceName* is required to reference the namespace instance when evaluated as an expression. In the example ```TypeScript -namespace A { - export interface X { s: string } +namespace A { + export interface X { s: string } } -namespace B { - var A = 1; - import Y = A; +namespace B { + var A = 1; + import Y = A; } ``` @@ -5360,10 +5359,10 @@ In the example ```TypeScript interface A { x: string; } -namespace M { - export interface B { x: A; } - export interface C { x: B; } - export function foo(c: C) { … } +namespace M { + export interface B { x: A; } + export interface C { x: B; } + export function foo(c: C) { … } } ``` @@ -5376,37 +5375,37 @@ Namespaces are "open-ended" and namespace declarations with the same qualified n File a.ts: ```TypeScript -namespace outer { - var local = 1; // Non-exported local variable - export var a = local; // outer.a - export namespace inner { - export var x = 10; // outer.inner.x - } +namespace outer { + var local = 1; // Non-exported local variable + export var a = local; // outer.a + export namespace inner { + export var x = 10; // outer.inner.x + } } ``` File b.ts: ```TypeScript -namespace outer { - var local = 2; // Non-exported local variable - export var b = local; // outer.b - export namespace inner { - export var y = 20; // outer.inner.y - } +namespace outer { + var local = 2; // Non-exported local variable + export var b = local; // outer.b + export namespace inner { + export var y = 20; // outer.inner.y + } } ``` Assuming the two source files are part of the same program, the two declarations will have the global namespace as their common root and will therefore contribute to the same namespace instance, the instance type of which will be: ```TypeScript -{ - a: number; - b: number; - inner: { - x: number; - y: number; - }; +{ + a: number; + b: number; + inner: { + x: number; + y: number; + }; } ``` @@ -5425,24 +5424,24 @@ When merging a non-ambient function or class declaration and a non-ambient names The example ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } -function point(x: number, y: number): Point { - return { x: x, y: y }; +function point(x: number, y: number): Point { + return { x: x, y: y }; } -namespace point { - export var origin = point(0, 0); - export function equals(p1: Point, p2: Point) { - return p1.x == p2.x && p1.y == p2.y; - } +namespace point { + export var origin = point(0, 0); + export function equals(p1: Point, p2: Point) { + return p1.x == p2.x && p1.y == p2.y; + } } -var p1 = point(0, 0); -var p2 = point.origin; +var p1 = point(0, 0); +var p2 = point.origin; var b = point.equals(p1, p2); ``` @@ -5453,9 +5452,9 @@ declares 'point' as a function object with two properties, 'origin' and 'equals' A namespace generates JavaScript code that is equivalent to the following: ```TypeScript -var ; -(function() { - +var ; +(function() { + })(||(={})); ``` @@ -5495,16 +5494,16 @@ TypeScript implements support for ECMAScript 2015 modules and supports down-leve A TypeScript ***program*** consists of one or more source files. -  *SourceFile:* -   *ImplementationSourceFile* +  *SourceFile:* +   *ImplementationSourceFile*    *DeclarationSourceFile* -  *ImplementationSourceFile:* -   *ImplementationScript* +  *ImplementationSourceFile:* +   *ImplementationScript*    *ImplementationModule* -  *DeclarationSourceFile:* -   *DeclarationScript* +  *DeclarationSourceFile:* +   *DeclarationScript*    *DeclarationModule* Source files with extension '.ts' are ***implementation source files*** containing statements and declarations, and source files with extension '.d.ts' are ***declaration source files*** containing declarations only. @@ -5527,46 +5526,46 @@ Any files included as dependencies in turn have their references analyzed in a t Source files that contain no module import or export declarations are classified as ***scripts***. Scripts form the single ***global namespace*** and entities declared in scripts are in scope everywhere in a program. -  *ImplementationScript:* +  *ImplementationScript:*    *ImplementationScriptElementsopt* -  *ImplementationScriptElements:* -   *ImplementationScriptElement* +  *ImplementationScriptElements:* +   *ImplementationScriptElement*    *ImplementationScriptElements* *ImplementationScriptElement* -  *ImplementationScriptElement:* -   *ImplementationElement* +  *ImplementationScriptElement:* +   *ImplementationElement*    *AmbientModuleDeclaration* -  *ImplementationElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *ImplementationElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* -  *DeclarationScript:* +  *DeclarationScript:*    *DeclarationScriptElementsopt* -  *DeclarationScriptElements:* -   *DeclarationScriptElement* +  *DeclarationScriptElements:* +   *DeclarationScriptElement*    *DeclarationScriptElements* *DeclarationScriptElement* -  *DeclarationScriptElement:* -   *DeclarationElement* +  *DeclarationScriptElement:* +   *DeclarationElement*    *AmbientModuleDeclaration* -  *DeclarationElement:* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *DeclarationElement:* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* The initialization order of the scripts that make up the global namespace ultimately depends on the order in which the generated JavaScript files are loaded at run-time (which, for example, may be controlled by <script/> tags that reference the generated JavaScript files). @@ -5575,37 +5574,37 @@ The initialization order of the scripts that make up the global namespace ultima Source files that contain at least one module import or export declaration are considered separate ***modules***. Non-exported entities declared in a module are in scope only in that module, but exported entities can be imported into other modules using import declarations. -  *ImplementationModule:* +  *ImplementationModule:*    *ImplementationModuleElementsopt* -  *ImplementationModuleElements:* -   *ImplementationModuleElement* +  *ImplementationModuleElements:* +   *ImplementationModuleElement*    *ImplementationModuleElements* *ImplementationModuleElement* -  *ImplementationModuleElement:* -   *ImplementationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ImportRequireDeclaration* -   *ExportImplementationElement* -   *ExportDefaultImplementationElement* -   *ExportListDeclaration* +  *ImplementationModuleElement:* +   *ImplementationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ImportRequireDeclaration* +   *ExportImplementationElement* +   *ExportDefaultImplementationElement* +   *ExportListDeclaration*    *ExportAssignment* -  *DeclarationModule:* +  *DeclarationModule:*    *DeclarationModuleElementsopt* -  *DeclarationModuleElements:* -   *DeclarationModuleElement* +  *DeclarationModuleElements:* +   *DeclarationModuleElement*    *DeclarationModuleElements* *DeclarationModuleElement* -  *DeclarationModuleElement:* -   *DeclarationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ExportDeclarationElement* -   *ExportDefaultDeclarationElement* -   *ExportListDeclaration* +  *DeclarationModuleElement:* +   *DeclarationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ExportDeclarationElement* +   *ExportDefaultDeclarationElement* +   *ExportListDeclaration*    *ExportAssignment* Initialization order of modules is determined by the module loader being used and is not specified by the TypeScript language. However, it is generally the case that non-circularly dependent modules are automatically loaded and initialized in the correct order. @@ -5615,13 +5614,13 @@ Modules can additionally be declared using *AmbientModuleDeclarations* in declar Below is an example of two modules written in separate source files: ```TypeScript -// -------- main.ts -------- -import { message } from "./log"; +// -------- main.ts -------- +import { message } from "./log"; message("hello"); -// -------- log.ts -------- -export function message(s: string) { - console.log(s); +// -------- log.ts -------- +export function message(s: string) { + console.log(s); } ``` @@ -5702,7 +5701,7 @@ imports the given module without creating any local bindings (this is useful onl Import require declarations exist for backward compatibility with earlier versions of TypeScript. -  *ImportRequireDeclaration:* +  *ImportRequireDeclaration:*    `import` *BindingIdentifier* `=` `require` `(` *StringLiteral* `)` `;` An import require declaration introduces a local identifier that references a given module. The string literal specified in an import require declaration is interpreted as a module name (section [11.3.1](#11.3.1)). The local identifier introduced by the declaration becomes an alias for, and is classified exactly like, the entity exported from the referenced module. Specifically, if the referenced module contains no export assignment the identifier is classified as a value and a namespace, and if the referenced module contains an export assignment the identifier is classified exactly like the entity named in the export assignment. @@ -5729,30 +5728,30 @@ An export declaration declares one or more exported module members. The exported In the body of a module, a declaration can export the declared entity by including an `export` modifier. -  *ExportImplementationElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportImplementationElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ExportDeclarationElement:* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *AmbientDeclaration* +  *ExportDeclarationElement:* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* In addition to introducing a name in the local declaration space of the module, an exported declaration introduces the same name with the same classification in the module's export declaration space. For example, the declaration ```TypeScript -export function point(x: number, y: number) { - return { x, y }; +export function point(x: number, y: number) { + return { x, y }; } ``` @@ -5762,30 +5761,30 @@ introduces a local name `point` and an exported name `point` that both reference Export default declarations provide short-hand syntax for exporting an entity named `default`. -  *ExportDefaultImplementationElement:* -   `export` `default` *FunctionDeclaration* -   `export` `default` *GeneratorDeclaration* -   `export` `default` *ClassDeclaration* +  *ExportDefaultImplementationElement:* +   `export` `default` *FunctionDeclaration* +   `export` `default` *GeneratorDeclaration* +   `export` `default` *ClassDeclaration*    `export` `default` *AssignmentExpression* `;` -  *ExportDefaultDeclarationElement:* -   `export` `default` *AmbientFunctionDeclaration* -   `export` `default` *AmbientClassDeclaration* +  *ExportDefaultDeclarationElement:* +   `export` `default` *AmbientFunctionDeclaration* +   `export` `default` *AmbientClassDeclaration*    `export` `default` *IdentifierReference* `;` An *ExportDefaultImplementationElement* or *ExportDefaultDeclarationElement* for a function, generator, or class introduces a value named `default`, and in the case of a class, a type named `default`, in the containing module's export declaration space. The declaration may optionally specify a local name for the exported function, generator, or class. For example, the declaration ```TypeScript -export default function point(x: number, y: number) { - return { x, y }; +export default function point(x: number, y: number) { + return { x, y }; } ``` introduces a local name `point` and an exported name `default` that both reference the function. The declaration is effectively equivalent to ```TypeScript -function point(x: number, y: number) { - return { x, y }; +function point(x: number, y: number) { + return { x, y }; } export default point; @@ -5794,8 +5793,8 @@ export default point; which again is equivalent to ```TypeScript -function point(x: number, y: number) { - return { x, y }; +function point(x: number, y: number) { + return { x, y }; } export { point as default }; @@ -5804,13 +5803,13 @@ export { point as default }; An *ExportDefaultImplementationElement* or *ExportDefaultDeclarationElement* for an expression consisting of a single identifier must name an entity declared in the current module or the global namespace. The declaration introduces an entity named `default`, with the same classification as the referenced entity, in the containing module's export declaration space. For example, the declarations ```TypeScript -interface Point { - x: number; - y: number; +interface Point { + x: number; + y: number; } -function Point(x: number, y: number): Point { - return { x, y }; +function Point(x: number, y: number): Point { + return { x, y }; } export default Point; @@ -5830,9 +5829,9 @@ introduces an exported value named `default` of type string. An export list declaration exports one or more entities from the current module or a specified module. -  *ExportListDeclaration:* -   `export` `*` *FromClause* `;` -   `export` *ExportClause* *FromClause* `;` +  *ExportListDeclaration:* +   `export` `*` *FromClause* `;` +   `export` *ExportClause* *FromClause* `;`    `export` *ExportClause* `;` An *ExportListDeclaration* without a *FromClause* exports entities from the current module. In a declaration of the form @@ -5883,7 +5882,7 @@ If a module contains an export assignment it is an error for the module to also Export assignments exist for backward compatibility with earlier versions of TypeScript. An export assignment designates a module member as the entity to be exported in place of the module itself. -  *ExportAssignment:* +  *ExportAssignment:*    `export` `=` *IdentifierReference* `;` A module containing an export assignment can be imported using an import require declaration ([11.3.3](#11.3.3)), and the local alias introduced by the import require declaration then takes on all meanings of the identifier named in the export assignment. @@ -5895,9 +5894,9 @@ Assume the following example resides in the file 'point.ts': ```TypeScript export = Point; -class Point { - constructor(public x: number, public y: number) { } - static origin = new Point(0, 0); +class Point { + constructor(public x: number, public y: number) { } + static origin = new Point(0, 0); } ``` @@ -5906,7 +5905,7 @@ When 'point.ts' is imported in another module, the import alias references the e ```TypeScript import Pt = require("./point"); -var p1 = new Pt(10, 20); +var p1 = new Pt(10, 20); var p2 = Pt.origin; ``` @@ -5921,16 +5920,16 @@ The 'main' and 'log' example from section [11.3](#11.3) above generates the foll File main.js: ```TypeScript -var log_1 = require("./log"); +var log_1 = require("./log"); log_1.message("hello"); ``` File log.js: ```TypeScript -function message(s) { - console.log(s); -} +function message(s) { + console.log(s); +} exports.message = message; ``` @@ -5943,29 +5942,29 @@ File geometry.ts: ```TypeScript export interface Point { x: number; y: number }; -export function point(x: number, y: number): Point { - return { x, y }; +export function point(x: number, y: number): Point { + return { x, y }; } ``` File game.ts: ```TypeScript -import * as g from "./geometry"; +import * as g from "./geometry"; let p = g.point(10, 20); ``` The 'game' module references the imported 'geometry' module in an expression (through its alias 'g') and a 'require' call is therefore included in the emitted JavaScript: ```TypeScript -var g = require("./geometry"); +var g = require("./geometry"); var p = g.point(10, 20); ``` Had the 'game' module instead been written to only reference 'geometry' in a type position ```TypeScript -import * as g from "./geometry"; +import * as g from "./geometry"; let p: g.Point = { x: 10, y: 20 }; ``` @@ -5984,19 +5983,19 @@ The "main" and "log" example from above generates the following JavaScript code File main.js: ```TypeScript -define(["require", "exports", "./log"], function(require, exports, log_1) { - log_1.message("hello"); +define(["require", "exports", "./log"], function(require, exports, log_1) { + log_1.message("hello"); } ``` File log.js: ```TypeScript -define(["require", "exports"], function(require, exports) { - function message(s) { - console.log(s); - } - exports.message = message; +define(["require", "exports"], function(require, exports) { + function message(s) { + console.log(s); + } + exports.message = message; } ``` @@ -6012,27 +6011,27 @@ Ambient declarations are used to provide static typing over existing JavaScript Ambient declarations are written using the `declare` keyword and can declare variables, functions, classes, enums, namespaces, or modules. -  *AmbientDeclaration:* -   `declare` *AmbientVariableDeclaration* -   `declare` *AmbientFunctionDeclaration* -   `declare` *AmbientClassDeclaration* -   `declare` *AmbientEnumDeclaration* +  *AmbientDeclaration:* +   `declare` *AmbientVariableDeclaration* +   `declare` *AmbientFunctionDeclaration* +   `declare` *AmbientClassDeclaration* +   `declare` *AmbientEnumDeclaration*    `declare` *AmbientNamespaceDeclaration* ### 12.1.1 Ambient Variable Declarations An ambient variable declaration introduces a variable in the containing declaration space. -  *AmbientVariableDeclaration:* -   `var` *AmbientBindingList* `;` -   `let` *AmbientBindingList* `;` +  *AmbientVariableDeclaration:* +   `var` *AmbientBindingList* `;` +   `let` *AmbientBindingList* `;`    `const` *AmbientBindingList* `;` -  *AmbientBindingList:* -   *AmbientBinding* +  *AmbientBindingList:* +   *AmbientBinding*    *AmbientBindingList* `,` *AmbientBinding* -  *AmbientBinding:* +  *AmbientBinding:*    *BindingIdentifier* *TypeAnnotationopt* An ambient variable declaration may optionally include a type annotation. If no type annotation is present, the variable is assumed to have type Any. @@ -6043,7 +6042,7 @@ An ambient variable declaration does not permit an initializer expression to be An ambient function declaration introduces a function in the containing declaration space. -  *AmbientFunctionDeclaration:* +  *AmbientFunctionDeclaration:*    `function` *BindingIdentifier* *CallSignature* `;` Ambient functions may be overloaded by specifying multiple ambient function declarations with the same name, but it is an error to declare multiple overloads that are considered identical (section [3.11.2](#3.11.2)) or differ only in their return types. @@ -6054,33 +6053,33 @@ Ambient function declarations cannot specify a function bodies and do not permit An ambient class declaration declares a class type and a constructor function in the containing declaration space. -  *AmbientClassDeclaration:* +  *AmbientClassDeclaration:*    `class` *BindingIdentifier* *TypeParametersopt* *ClassHeritage* `{` *AmbientClassBody* `}` -  *AmbientClassBody:* +  *AmbientClassBody:*    *AmbientClassBodyElementsopt* -  *AmbientClassBodyElements:* -   *AmbientClassBodyElement* +  *AmbientClassBodyElements:* +   *AmbientClassBodyElement*    *AmbientClassBodyElements* *AmbientClassBodyElement* -  *AmbientClassBodyElement:* -   *AmbientConstructorDeclaration* -   *AmbientPropertyMemberDeclaration* +  *AmbientClassBodyElement:* +   *AmbientConstructorDeclaration* +   *AmbientPropertyMemberDeclaration*    *IndexSignature* -  *AmbientConstructorDeclaration:* +  *AmbientConstructorDeclaration:*    `constructor` `(` *ParameterListopt* `)` `;` -  *AmbientPropertyMemberDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;` +  *AmbientPropertyMemberDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` ### 12.1.4 Ambient Enum Declarations An ambient enum is grammatically equivalent to a non-ambient enum declaration. -  *AmbientEnumDeclaration:* +  *AmbientEnumDeclaration:*    *EnumDeclaration* Ambient enum declarations differ from non-ambient enum declarations in two ways: @@ -6094,24 +6093,24 @@ Ambient enum declarations are otherwise processed in the same manner as non-ambi An ambient namespace declaration declares a namespace. -  *AmbientNamespaceDeclaration:* +  *AmbientNamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *AmbientNamespaceBody* `}` -  *AmbientNamespaceBody:* +  *AmbientNamespaceBody:*    *AmbientNamespaceElementsopt* -  *AmbientNamespaceElements:* -   *AmbientNamespaceElement* +  *AmbientNamespaceElements:* +   *AmbientNamespaceElement*    *AmbientNamespaceElements* *AmbientNamespaceElement* -  *AmbientNamespaceElement:* -   `export`*opt* *AmbientVariableDeclaration* -   `export`*opt* *AmbientLexicalDeclaration* -   `export`*opt* *AmbientFunctionDeclaration* -   `export`*opt* *AmbientClassDeclaration* -   `export`*opt* *InterfaceDeclaration* -   `export`*opt* *AmbientEnumDeclaration* -   `export`*opt* *AmbientNamespaceDeclaration* +  *AmbientNamespaceElement:* +   `export`*opt* *AmbientVariableDeclaration* +   `export`*opt* *AmbientLexicalDeclaration* +   `export`*opt* *AmbientFunctionDeclaration* +   `export`*opt* *AmbientClassDeclaration* +   `export`*opt* *InterfaceDeclaration* +   `export`*opt* *AmbientEnumDeclaration* +   `export`*opt* *AmbientNamespaceDeclaration*    `export`*opt* *ImportAliasDeclaration* Except for *ImportAliasDeclarations*, *AmbientNamespaceElements* always declare exported entities regardless of whether they include the optional `export` modifier. @@ -6120,7 +6119,7 @@ Except for *ImportAliasDeclarations*, *AmbientNamespaceElements* always declare An *AmbientModuleDeclaration* declares a module. This type of declaration is permitted only at the top level in a source file that contributes to the global namespace (section [11.1](#11.1)). The *StringLiteral* must specify a top-level module name. Relative module names are not permitted. -  *AmbientModuleDeclaration:* +  *AmbientModuleDeclaration:*    `declare` `module` *StringLiteral* `{`  *DeclarationModule* `}` An *ImportRequireDeclaration* in an *AmbientModuleDeclaration* may reference other modules only through top-level module names. Relative module names are not permitted. @@ -6130,21 +6129,21 @@ If an ambient module declaration includes an export assignment, it is an error f Ambient modules are "open-ended" and ambient module declarations with the same string literal name contribute to a single module. For example, the following two declarations of a module 'io' might be located in separate source files. ```TypeScript -declare module "io" { - export function readFile(filename: string): string; +declare module "io" { + export function readFile(filename: string): string; } -declare module "io" { - export function writeFile(filename: string, data: string): void; +declare module "io" { + export function writeFile(filename: string, data: string): void; } ``` This has the same effect as a single combined declaration: ```TypeScript -declare module "io" { - export function readFile(filename: string): string; - export function writeFile(filename: string, data: string): void; +declare module "io" { + export function readFile(filename: string): string; + export function writeFile(filename: string, data: string): void; } ``` @@ -6156,583 +6155,584 @@ This appendix contains a summary of the grammar found in the main document. As d ## A.1 Types -  *TypeParameters:* +  *TypeParameters:*    `<` *TypeParameterList* `>` -  *TypeParameterList:* -   *TypeParameter* +  *TypeParameterList:* +   *TypeParameter*    *TypeParameterList* `,` *TypeParameter* -  *TypeParameter:* +  *TypeParameter:*    *BindingIdentifier* *Constraintopt* -  *Constraint:* +  *Constraint:*    `extends` *Type* -  *TypeArguments:* +  *TypeArguments:*    `<` *TypeArgumentList* `>` -  *TypeArgumentList:* -   *TypeArgument* +  *TypeArgumentList:* +   *TypeArgument*    *TypeArgumentList* `,` *TypeArgument* -  *TypeArgument:* +  *TypeArgument:*    *Type* -  *Type:* -   *UnionOrIntersectionOrPrimaryType* -   *FunctionType* +  *Type:* +   *UnionOrIntersectionOrPrimaryType* +   *FunctionType*    *ConstructorType* -  *UnionOrIntersectionOrPrimaryType:* -   *UnionType* +  *UnionOrIntersectionOrPrimaryType:* +   *UnionType*    *IntersectionOrPrimaryType* -  *IntersectionOrPrimaryType:* -   *IntersectionType* +  *IntersectionOrPrimaryType:* +   *IntersectionType*    *PrimaryType* -  *PrimaryType:* -   *ParenthesizedType* -   *PredefinedType* -   *TypeReference* -   *ObjectType* -   *ArrayType* -   *TupleType* -   *TypeQuery* +  *PrimaryType:* +   *ParenthesizedType* +   *PredefinedType* +   *TypeReference* +   *ObjectType* +   *ArrayType* +   *TupleType* +   *TypeQuery*    *ThisType* -  *ParenthesizedType:* +  *ParenthesizedType:*    `(` *Type* `)` -  *PredefinedType:* -   `any` -   `number` -   `boolean` -   `string` -   `symbol` +  *PredefinedType:* +   `any` +   `number` +   `boolean` +   `string` +   `symbol`    `void` -  *TypeReference:* +  *TypeReference:*    *TypeName* *[no LineTerminator here]* *TypeArgumentsopt* -  *TypeName:* -   *IdentifierReference* +  *TypeName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* -  *NamespaceName:* -   *IdentifierReference* +  *NamespaceName:* +   *IdentifierReference*    *NamespaceName* `.` *IdentifierReference* -  *ObjectType:* +  *ObjectType:*    `{` *TypeBodyopt* `}` -  *TypeBody:* -   *TypeMemberList* `;`*opt* +  *TypeBody:* +   *TypeMemberList* `;`*opt*    *TypeMemberList* `,`*opt* -  *TypeMemberList:* -   *TypeMember* -   *TypeMemberList* `;` *TypeMember* +  *TypeMemberList:* +   *TypeMember* +   *TypeMemberList* `;` *TypeMember*    *TypeMemberList* `,` *TypeMember* -  *TypeMember:* -   *PropertySignature* -   *CallSignature* -   *ConstructSignature* -   *IndexSignature* +  *TypeMember:* +   *PropertySignature* +   *CallSignature* +   *ConstructSignature* +   *IndexSignature*    *MethodSignature* -  *ArrayType:* +  *ArrayType:*    *PrimaryType* *[no LineTerminator here]* `[` `]` -  *TupleType:* +  *TupleType:*    `[` *TupleElementTypes* `]` -  *TupleElementTypes:* -   *TupleElementType* +  *TupleElementTypes:* +   *TupleElementType*    *TupleElementTypes* `,` *TupleElementType* -  *TupleElementType:* +  *TupleElementType:*    *Type* -  *UnionType:* +  *UnionType:*    *UnionOrIntersectionOrPrimaryType* `|` *IntersectionOrPrimaryType* -  *IntersectionType:* +  *IntersectionType:*    *IntersectionOrPrimaryType* `&` *PrimaryType* -  *FunctionType:* +  *FunctionType:*    *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* -  *ConstructorType:* +  *ConstructorType:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` `=>` *Type* -  *TypeQuery:* +  *TypeQuery:*    `typeof` *TypeQueryExpression* -  *TypeQueryExpression:* -   *IdentifierReference* +  *TypeQueryExpression:* +   *IdentifierReference*    *TypeQueryExpression* `.` *IdentifierName* -  *ThisType:* +  *ThisType:*    `this` -  *PropertySignature:* +  *PropertySignature:*    *PropertyName* `?`*opt* *TypeAnnotationopt* -  *PropertyName:* -   *IdentifierName* -   *StringLiteral* +  *PropertyName:* +   *IdentifierName* +   *StringLiteral*    *NumericLiteral* -  *TypeAnnotation:* +  *TypeAnnotation:*    `:` *Type* -  *CallSignature:* +  *CallSignature:*    *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* -  *ParameterList:* -   *RequiredParameterList* -   *OptionalParameterList* -   *RestParameter* -   *RequiredParameterList* `,` *OptionalParameterList* -   *RequiredParameterList* `,` *RestParameter* -   *OptionalParameterList* `,` *RestParameter* +  *ParameterList:* +   *RequiredParameterList* +   *OptionalParameterList* +   *RestParameter* +   *RequiredParameterList* `,` *OptionalParameterList* +   *RequiredParameterList* `,` *RestParameter* +   *OptionalParameterList* `,` *RestParameter*    *RequiredParameterList* `,` *OptionalParameterList* `,` *RestParameter* -  *RequiredParameterList:* -   *RequiredParameter* +  *RequiredParameterList:* +   *RequiredParameter*    *RequiredParameterList* `,` *RequiredParameter* -  *RequiredParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* +  *RequiredParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt*    *BindingIdentifier* `:` *StringLiteral* -  *AccessibilityModifier:* -   `public` -   `private` +  *AccessibilityModifier:* +   `public` +   `private`    `protected` -  *BindingIdentifierOrPattern:* -   *BindingIdentifier* +  *BindingIdentifierOrPattern:* +   *BindingIdentifier*    *BindingPattern* -  *OptionalParameterList:* -   *OptionalParameter* +  *OptionalParameterList:* +   *OptionalParameter*    *OptionalParameterList* `,` *OptionalParameter* -  *OptionalParameter:* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* -   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer* +  *OptionalParameter:* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* `?` *TypeAnnotationopt* +   *AccessibilityModifieropt* *BindingIdentifierOrPattern* *TypeAnnotationopt* *Initializer*    *BindingIdentifier* `?` `:` *StringLiteral* -  *RestParameter:* +  *RestParameter:*    `...` *BindingIdentifier* *TypeAnnotationopt* -  *ConstructSignature:* +  *ConstructSignature:*    `new` *TypeParametersopt* `(` *ParameterListopt* `)` *TypeAnnotationopt* -  *IndexSignature:* -   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation* +  *IndexSignature:* +   `[` *BindingIdentifier* `:` `string` `]` *TypeAnnotation*    `[` *BindingIdentifier* `:` `number` `]` *TypeAnnotation* -  *MethodSignature:* +  *MethodSignature:*    *PropertyName* `?`*opt* *CallSignature* -  *TypeAliasDeclaration:* +  *TypeAliasDeclaration:*    `type` *BindingIdentifier* *TypeParametersopt* `=` *Type* `;` ## A.2 Expressions -  *PropertyDefinition:* *( Modified )* -   *IdentifierReference* -   *CoverInitializedName* -   *PropertyName* `:` *AssignmentExpression* -   *PropertyName* *CallSignature* `{` *FunctionBody* `}` -   *GetAccessor* +  *PropertyDefinition:* *( Modified )* +   *IdentifierReference* +   *CoverInitializedName* +   *PropertyName* `:` *AssignmentExpression* +   *PropertyName* *CallSignature* `{` *FunctionBody* `}` +   *GetAccessor*    *SetAccessor* -  *GetAccessor:* +  *GetAccessor:*    `get` *PropertyName* `(` `)` *TypeAnnotationopt* `{` *FunctionBody* `}` -  *SetAccessor:* +  *SetAccessor:*    `set` *PropertyName* `(` *BindingIdentifierOrPattern* *TypeAnnotationopt* `)` `{` *FunctionBody* `}` -  *FunctionExpression:* *( Modified )* +  *FunctionExpression:* *( Modified )*    `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` -  *ArrowFormalParameters:* *( Modified )* +  *ArrowFormalParameters:* *( Modified )*    *CallSignature* -  *Arguments:* *( Modified )* +  *Arguments:* *( Modified )*    *TypeArgumentsopt* `(` *ArgumentListopt* `)` -  *UnaryExpression:* *( Modified )* -   … +  *UnaryExpression:* *( Modified )* +   …    `<` *Type* `>` *UnaryExpression* ## A.3 Statements -  *Declaration:* *( Modified )* -   … -   *InterfaceDeclaration* -   *TypeAliasDeclaration* +  *Declaration:* *( Modified )* +   … +   *InterfaceDeclaration* +   *TypeAliasDeclaration*    *EnumDeclaration* -  *VariableDeclaration:* *( Modified )* -   *SimpleVariableDeclaration* +  *VariableDeclaration:* *( Modified )* +   *SimpleVariableDeclaration*    *DestructuringVariableDeclaration* -  *SimpleVariableDeclaration:* +  *SimpleVariableDeclaration:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* -  *DestructuringVariableDeclaration:* +  *DestructuringVariableDeclaration:*    *BindingPattern* *TypeAnnotationopt* *Initializer* -  *LexicalBinding:* *( Modified )* -   *SimpleLexicalBinding* +  *LexicalBinding:* *( Modified )* +   *SimpleLexicalBinding*    *DestructuringLexicalBinding* -  *SimpleLexicalBinding:* +  *SimpleLexicalBinding:*    *BindingIdentifier* *TypeAnnotationopt* *Initializeropt* -  *DestructuringLexicalBinding:* +  *DestructuringLexicalBinding:*    *BindingPattern* *TypeAnnotationopt* *Initializeropt* ## A.4 Functions -  *FunctionDeclaration:* *( Modified )* -   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}` +  *FunctionDeclaration:* *( Modified )* +   `function` *BindingIdentifieropt* *CallSignature* `{` *FunctionBody* `}`    `function` *BindingIdentifieropt* *CallSignature* `;` ## A.5 Interfaces -  *InterfaceDeclaration:* +  *InterfaceDeclaration:*    `interface` *BindingIdentifier* *TypeParametersopt* *InterfaceExtendsClauseopt* *ObjectType* -  *InterfaceExtendsClause:* +  *InterfaceExtendsClause:*    `extends` *ClassOrInterfaceTypeList* -  *ClassOrInterfaceTypeList:* -   *ClassOrInterfaceType* +  *ClassOrInterfaceTypeList:* +   *ClassOrInterfaceType*    *ClassOrInterfaceTypeList* `,` *ClassOrInterfaceType* -  *ClassOrInterfaceType:* +  *ClassOrInterfaceType:*    *TypeReference* ## A.6 Classes -  *ClassDeclaration:* *( Modified )* +  *ClassDeclaration:* *( Modified )*    `class` *BindingIdentifieropt* *TypeParametersopt* *ClassHeritage* `{` *ClassBody* `}` -  *ClassHeritage:* *( Modified )* +  *ClassHeritage:* *( Modified )*    *ClassExtendsClauseopt* *ImplementsClauseopt* -  *ClassExtendsClause:* +  *ClassExtendsClause:*    `extends`  *ClassType* -  *ClassType:* +  *ClassType:*    *TypeReference* -  *ImplementsClause:* +  *ImplementsClause:*    `implements` *ClassOrInterfaceTypeList* -  *ClassElement:* *( Modified )* -   *ConstructorDeclaration* -   *PropertyMemberDeclaration* +  *ClassElement:* *( Modified )* +   *ConstructorDeclaration* +   *PropertyMemberDeclaration*    *IndexMemberDeclaration* -  *ConstructorDeclaration:* -   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}` +  *ConstructorDeclaration:* +   *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `{` *FunctionBody* `}`    *AccessibilityModifieropt* `constructor` `(` *ParameterListopt* `)` `;` -  *PropertyMemberDeclaration:* -   *MemberVariableDeclaration* -   *MemberFunctionDeclaration* +  *PropertyMemberDeclaration:* +   *MemberVariableDeclaration* +   *MemberFunctionDeclaration*    *MemberAccessorDeclaration* -  *MemberVariableDeclaration:* +  *MemberVariableDeclaration:*    *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* *Initializeropt* `;` -  *MemberFunctionDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}` +  *MemberFunctionDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `{` *FunctionBody* `}`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` -  *MemberAccessorDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *GetAccessor* +  *MemberAccessorDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *GetAccessor*    *AccessibilityModifieropt* `static`*opt* *SetAccessor* -  *IndexMemberDeclaration:* +  *IndexMemberDeclaration:*    *IndexSignature* `;` ## A.7 Enums -  *EnumDeclaration:* +  *EnumDeclaration:*    `const`*opt* `enum` *BindingIdentifier* `{` *EnumBodyopt* `}` -  *EnumBody:* +  *EnumBody:*    *EnumMemberList* `,`*opt* -  *EnumMemberList:* -   *EnumMember* +  *EnumMemberList:* +   *EnumMember*    *EnumMemberList* `,` *EnumMember* -  *EnumMember:* -   *PropertyName* +  *EnumMember:* +   *PropertyName*    *PropertyName* = *EnumValue* -  *EnumValue:* +  *EnumValue:*    *AssignmentExpression* ## A.8 Namespaces -  *NamespaceDeclaration:* +  *NamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *NamespaceBody* `}` -  *IdentifierPath:* -   *BindingIdentifier* +  *IdentifierPath:* +   *BindingIdentifier*    *IdentifierPath* `.` *BindingIdentifier* -  *NamespaceBody:* +  *NamespaceBody:*    *NamespaceElementsopt* -  *NamespaceElements:* -   *NamespaceElement* +  *NamespaceElements:* +   *NamespaceElement*    *NamespaceElements* *NamespaceElement* -  *NamespaceElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration -   AmbientDeclaration -   ImportAliasDeclaration +  *NamespaceElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration +   AmbientDeclaration +   ImportAliasDeclaration    ExportNamespaceElement* -  *ExportNamespaceElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportNamespaceElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ImportAliasDeclaration:* +  *ImportAliasDeclaration:*    `import` *BindingIdentifier* `=` *EntityName* `;` -  *EntityName:* -   *NamespaceName* +  *EntityName:* +   *NamespaceName*    *NamespaceName* `.` *IdentifierReference* ## A.9 Scripts and Modules -  *SourceFile:* -   *ImplementationSourceFile* +  *SourceFile:* +   *ImplementationSourceFile*    *DeclarationSourceFile* -  *ImplementationSourceFile:* -   *ImplementationScript* +  *ImplementationSourceFile:* +   *ImplementationScript*    *ImplementationModule* -  *DeclarationSourceFile:* -   *DeclarationScript* +  *DeclarationSourceFile:* +   *DeclarationScript*    *DeclarationModule* -  *ImplementationScript:* +  *ImplementationScript:*    *ImplementationScriptElementsopt* -  *ImplementationScriptElements:* -   *ImplementationScriptElement* +  *ImplementationScriptElements:* +   *ImplementationScriptElement*    *ImplementationScriptElements* *ImplementationScriptElement* -  *ImplementationScriptElement:* -   *ImplementationElement* +  *ImplementationScriptElement:* +   *ImplementationElement*    *AmbientModuleDeclaration* -  *ImplementationElement:* -   *Statement* -   *LexicalDeclaration* -   *FunctionDeclaration* -   *GeneratorDeclaration* -   *ClassDeclaration* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *EnumDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *ImplementationElement:* +   *Statement* +   *LexicalDeclaration* +   *FunctionDeclaration* +   *GeneratorDeclaration* +   *ClassDeclaration* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *EnumDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* -  *DeclarationScript:* +  *DeclarationScript:*    *DeclarationScriptElementsopt* -  *DeclarationScriptElements:* -   *DeclarationScriptElement* +  *DeclarationScriptElements:* +   *DeclarationScriptElement*    *DeclarationScriptElements* *DeclarationScriptElement* -  *DeclarationScriptElement:* -   *DeclarationElement* +  *DeclarationScriptElement:* +   *DeclarationElement*    *AmbientModuleDeclaration* -  *DeclarationElement:* -   *InterfaceDeclaration* -   *TypeAliasDeclaration* -   *NamespaceDeclaration* -   *AmbientDeclaration* +  *DeclarationElement:* +   *InterfaceDeclaration* +   *TypeAliasDeclaration* +   *NamespaceDeclaration* +   *AmbientDeclaration*    *ImportAliasDeclaration* -  *ImplementationModule:* +  *ImplementationModule:*    *ImplementationModuleElementsopt* -  *ImplementationModuleElements:* -   *ImplementationModuleElement* +  *ImplementationModuleElements:* +   *ImplementationModuleElement*    *ImplementationModuleElements* *ImplementationModuleElement* -  *ImplementationModuleElement:* -   *ImplementationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ImportRequireDeclaration* -   *ExportImplementationElement* -   *ExportDefaultImplementationElement* -   *ExportListDeclaration* +  *ImplementationModuleElement:* +   *ImplementationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ImportRequireDeclaration* +   *ExportImplementationElement* +   *ExportDefaultImplementationElement* +   *ExportListDeclaration*    *ExportAssignment* -  *DeclarationModule:* +  *DeclarationModule:*    *DeclarationModuleElementsopt* -  *DeclarationModuleElements:* -   *DeclarationModuleElement* +  *DeclarationModuleElements:* +   *DeclarationModuleElement*    *DeclarationModuleElements* *DeclarationModuleElement* -  *DeclarationModuleElement:* -   *DeclarationElement* -   *ImportDeclaration* -   *ImportAliasDeclaration* -   *ExportDeclarationElement* -   *ExportDefaultDeclarationElement* -   *ExportListDeclaration* +  *DeclarationModuleElement:* +   *DeclarationElement* +   *ImportDeclaration* +   *ImportAliasDeclaration* +   *ExportDeclarationElement* +   *ExportDefaultDeclarationElement* +   *ExportListDeclaration*    *ExportAssignment* -  *ImportRequireDeclaration:* +  *ImportRequireDeclaration:*    `import` *BindingIdentifier* `=` `require` `(` *StringLiteral* `)` `;` -  *ExportImplementationElement:* -   `export` *VariableStatement* -   `export` *LexicalDeclaration* -   `export` *FunctionDeclaration* -   `export` *GeneratorDeclaration* -   `export` *ClassDeclaration* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *EnumDeclaration* -   `export` *NamespaceDeclaration* -   `export` *AmbientDeclaration* +  *ExportImplementationElement:* +   `export` *VariableStatement* +   `export` *LexicalDeclaration* +   `export` *FunctionDeclaration* +   `export` *GeneratorDeclaration* +   `export` *ClassDeclaration* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *EnumDeclaration* +   `export` *NamespaceDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ExportDeclarationElement:* -   `export` *InterfaceDeclaration* -   `export` *TypeAliasDeclaration* -   `export` *AmbientDeclaration* +  *ExportDeclarationElement:* +   `export` *InterfaceDeclaration* +   `export` *TypeAliasDeclaration* +   `export` *AmbientDeclaration*    `export` *ImportAliasDeclaration* -  *ExportDefaultImplementationElement:* -   `export` `default` *FunctionDeclaration* -   `export` `default` *GeneratorDeclaration* -   `export` `default` *ClassDeclaration* +  *ExportDefaultImplementationElement:* +   `export` `default` *FunctionDeclaration* +   `export` `default` *GeneratorDeclaration* +   `export` `default` *ClassDeclaration*    `export` `default` *AssignmentExpression* `;` -  *ExportDefaultDeclarationElement:* -   `export` `default` *AmbientFunctionDeclaration* -   `export` `default` *AmbientClassDeclaration* +  *ExportDefaultDeclarationElement:* +   `export` `default` *AmbientFunctionDeclaration* +   `export` `default` *AmbientClassDeclaration*    `export` `default` *IdentifierReference* `;` -  *ExportListDeclaration:* -   `export` `*` *FromClause* `;` -   `export` *ExportClause* *FromClause* `;` +  *ExportListDeclaration:* +   `export` `*` *FromClause* `;` +   `export` *ExportClause* *FromClause* `;`    `export` *ExportClause* `;` -  *ExportAssignment:* +  *ExportAssignment:*    `export` `=` *IdentifierReference* `;` ## A.10 Ambients -  *AmbientDeclaration:* -   `declare` *AmbientVariableDeclaration* -   `declare` *AmbientFunctionDeclaration* -   `declare` *AmbientClassDeclaration* -   `declare` *AmbientEnumDeclaration* +  *AmbientDeclaration:* +   `declare` *AmbientVariableDeclaration* +   `declare` *AmbientFunctionDeclaration* +   `declare` *AmbientClassDeclaration* +   `declare` *AmbientEnumDeclaration*    `declare` *AmbientNamespaceDeclaration* -  *AmbientVariableDeclaration:* -   `var` *AmbientBindingList* `;` -   `let` *AmbientBindingList* `;` +  *AmbientVariableDeclaration:* +   `var` *AmbientBindingList* `;` +   `let` *AmbientBindingList* `;`    `const` *AmbientBindingList* `;` -  *AmbientBindingList:* -   *AmbientBinding* +  *AmbientBindingList:* +   *AmbientBinding*    *AmbientBindingList* `,` *AmbientBinding* -  *AmbientBinding:* +  *AmbientBinding:*    *BindingIdentifier* *TypeAnnotationopt* -  *AmbientFunctionDeclaration:* +  *AmbientFunctionDeclaration:*    `function` *BindingIdentifier* *CallSignature* `;` -  *AmbientClassDeclaration:* +  *AmbientClassDeclaration:*    `class` *BindingIdentifier* *TypeParametersopt* *ClassHeritage* `{` *AmbientClassBody* `}` -  *AmbientClassBody:* +  *AmbientClassBody:*    *AmbientClassBodyElementsopt* -  *AmbientClassBodyElements:* -   *AmbientClassBodyElement* +  *AmbientClassBodyElements:* +   *AmbientClassBodyElement*    *AmbientClassBodyElements* *AmbientClassBodyElement* -  *AmbientClassBodyElement:* -   *AmbientConstructorDeclaration* -   *AmbientPropertyMemberDeclaration* +  *AmbientClassBodyElement:* +   *AmbientConstructorDeclaration* +   *AmbientPropertyMemberDeclaration*    *IndexSignature* -  *AmbientConstructorDeclaration:* +  *AmbientConstructorDeclaration:*    `constructor` `(` *ParameterListopt* `)` `;` -  *AmbientPropertyMemberDeclaration:* -   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;` +  *AmbientPropertyMemberDeclaration:* +   *AccessibilityModifieropt* `static`*opt* *PropertyName* *TypeAnnotationopt* `;`    *AccessibilityModifieropt* `static`*opt* *PropertyName* *CallSignature* `;` -  *AmbientEnumDeclaration:* +  *AmbientEnumDeclaration:*    *EnumDeclaration* -  *AmbientNamespaceDeclaration:* +  *AmbientNamespaceDeclaration:*    `namespace` *IdentifierPath* `{` *AmbientNamespaceBody* `}` -  *AmbientNamespaceBody:* +  *AmbientNamespaceBody:*    *AmbientNamespaceElementsopt* -  *AmbientNamespaceElements:* -   *AmbientNamespaceElement* +  *AmbientNamespaceElements:* +   *AmbientNamespaceElement*    *AmbientNamespaceElements* *AmbientNamespaceElement* -  *AmbientNamespaceElement:* -   `export`*opt* *AmbientVariableDeclaration* -   `export`*opt* *AmbientLexicalDeclaration* -   `export`*opt* *AmbientFunctionDeclaration* -   `export`*opt* *AmbientClassDeclaration* -   `export`*opt* *InterfaceDeclaration* -   `export`*opt* *AmbientEnumDeclaration* -   `export`*opt* *AmbientNamespaceDeclaration* +  *AmbientNamespaceElement:* +   `export`*opt* *AmbientVariableDeclaration* +   `export`*opt* *AmbientLexicalDeclaration* +   `export`*opt* *AmbientFunctionDeclaration* +   `export`*opt* *AmbientClassDeclaration* +   `export`*opt* *InterfaceDeclaration* +   `export`*opt* *AmbientEnumDeclaration* +   `export`*opt* *AmbientNamespaceDeclaration*    `export`*opt* *ImportAliasDeclaration* -  *AmbientModuleDeclaration:* +  *AmbientModuleDeclaration:*    `declare` `module` *StringLiteral* `{`  *DeclarationModule* `}` + diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1ed033728d7d2..3f593bf2f553b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19813,6 +19813,10 @@ namespace ts { } } + checkSourceElement(node.body); + registerForUnusedIdentifiersCheck(node); + +/* // TODO(pcj): Document what this is doing if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { checkSourceElement(node.body); @@ -19821,7 +19825,7 @@ namespace ts { else { checkNodeDeferred(node); } - + */ } function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) { From 7dbf75d65b34ca435dc46bdc7b3eabe1281fd644 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Sat, 2 Dec 2017 13:54:55 -0700 Subject: [PATCH 7/9] Restore baseline test functions Test output looking reasonable, no errors seen. --- src/compiler/checker.ts | 7 +- src/compiler/diagnosticMessages.json | 4 - src/services/jsDoc.ts | 1 - tests/cases/compiler/noImplicitOverride.ts | 131 +++++++++++++++--- tests/cases/compiler/overrideKeywordEs5.ts | 14 +- .../fourslash/completionInJSDocFunctionNew.ts | 2 +- .../completionInJSDocFunctionThis.ts | 2 +- 7 files changed, 127 insertions(+), 34 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3f593bf2f553b..b008c19ab6102 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19765,6 +19765,7 @@ namespace ts { checkDecorators(node); + // TODO(pcj): @andy-ms says remove this if (getModifierFlags(node) & ModifierFlags.Override) { checkOverrideDeclaration(node); } @@ -22655,9 +22656,9 @@ namespace ts { const foundSymbol = getTargetSymbol(found); let errorInfo = chainDiagnosticMessages( undefined, - Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1, + Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_inherited_from_1, symbolToString(derived), - symbolToString(found) + symbolToString(objectType) ); if (!isPropertyIdenticalTo(derived, foundSymbol)) { errorInfo = chainDiagnosticMessages( @@ -22771,7 +22772,7 @@ namespace ts { && !(derivedDeclarationFlags & ModifierFlags.Abstract) && !(derivedDeclarationFlags & ModifierFlags.Override)) { error(getDeclarationName(derived.valueDeclaration), - Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_augmented_from_Object_1, + Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_inherited_from_1, symbolToString(derived), typeToString(baseType)); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ff3a4de6b56d7..383d2d6c69721 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1984,10 +1984,6 @@ "category": "Error", "code": 2570 }, - "Class member '{0}' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.{1})": { - "category": "Error", - "code": 2571 - }, "Override modifier cannot be used with an optional property declaration": { "category": "Error", "code": 2572 diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 84e21f69658a5..79b08780226f1 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -33,7 +33,6 @@ namespace ts.JsDoc { "prop", "property", "public", - "override", "requires", "returns", "see", diff --git a/tests/cases/compiler/noImplicitOverride.ts b/tests/cases/compiler/noImplicitOverride.ts index ab1aa1579b79f..366309f11435d 100644 --- a/tests/cases/compiler/noImplicitOverride.ts +++ b/tests/cases/compiler/noImplicitOverride.ts @@ -1,55 +1,140 @@ // @noImplicitOverride: true // @target: es5 -class Base { - get name(): string { - return 'Base'; - } - getMeaningOfLife(): number { return 42; } - public userId: number = 1; -} +// ****************************************************** +// First set of cases deal with inheritance from Object. +// ****************************************************** -class RejectWhenOverrideMissingOnInheritedMethod extends Object { +class RejectWhenOverrideAbsentOnInheritedMethod extends Object { toString(): string { return 'foo'; }; - hasOwnProperty(prop: string): boolean { - return super.hasOwnProperty(prop); - } +} +class AcceptWhenOverridePresentOnInheritedMethod extends Object { + override toString(): string { return 'foo'; }; } -class RejectWhenOverrideMissingOnAugmentedProperty { +// Similar to previous cases where augmentation from Object is implicit +class RejectWhenOverrideAbsentOnAugmentedProperty { toString(): string { return 'foo'; }; - hasOwnProperty(prop: string): boolean { - return false; - } +} +class AcceptWhenOverridePresentOnAugumentedProperty extends Object { + override toString(): string { return 'foo'; }; } +// This should fail via type mismatch of the return value. +// (test is not specific to the override checking code) class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { - hasOwnProperty(prop: string): number { + toString(): number { return -1; } } -class RejectWhenOverrideMissingOnInheritedProperty extends Base { +// ****************************************************** +// Next set of cases deal with inheritance derived from +// an explicitly defined class. +// ****************************************************** + +class Base { + // Public property + public userId: number = 1; + // Accessor + get name(): string { return 'Base'; } + // Typical public method + getMeaningOfLife(): number { return 42; } + // Private method + private processInternal(): void { } +} + +class RejectWhenOverrideAbsentOnInheritedProperty extends Base { public userId = 2; } +class AcceptWhenOverridePresentOnInheritedProperty extends Base { + public override userId = 2; +} -class RejectWhenOverrideMissingOnInheritedAccessor extends Base { +class RejectWhenOverrideAbsentOnInheritedAccessor extends Base { get name(): string { return 'foo'; }; } +class AcceptWhenOverridePresentOnInheritedAccessor extends Base { + override get name(): string { return 'foo'; }; +} + +class RejectWhenOverrideAbsentOnInheritedMethod extends Base { + getMeaningOfLife(): number { return 24; }; +} +class AcceptWhenOverridePresentOnInheritedMethod extends Base { + override getMeaningOfLife(): number { return 24; }; +} + +class RejectWhenOverridePresentWithPrivateModifier extends Base { + private override processInternal() { } +} + +// ****************************************************** +// Next set of cases deal with override within interfaces +// and abstract classes (where is should not be present). +// ****************************************************** interface Shape { getWidth(): number; } -interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape { +interface RejectWhenOverridePresentOnInterfaceDeclaration extends Shape { override getWidth(): number; } -interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape { - // abstract members don't need to be declared override +interface AcceptWhenOverrideAbsentOnInterfaceDeclaration extends Shape { getWidth(): number; } -class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { - /** @override */ public userId: number = 2; +// ****************************************************** +// Next set of cases deal with override with abstract +// classes. +// ****************************************************** + +abstract class Animal { + protected readonly name: string + + constructor(name: string) { + this.name = name; + } + + abstract speak(): string; +} + +abstract class RejectWhenOverridePresentWithAbstractModifier extends Animal { + abstract override speak(): string; +} + +abstract class AcceptWhenOverridePresentOnConcreteDeclaration extends Animal { + override speak(): string { return "Woof!"; } } + +// ****************************************************** +// Next set of cases deal with override with mixins +// ****************************************************** + +const mixin = {}>(Base: BC) => class extends Base { + mixedIn() {} +}; + +class A { + normal() {} +} + +class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(A) { + normal() {} + mixedIn() {} +} + +class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(A) { + override normal() {} + override mixedIn() {} +} + +// ******************************************************** +// Next set of cases deal with override specified via JsDoc +// ******************************************************** + +//class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { +// /** @override */ public speak(): string { return "Woof!" } +//} diff --git a/tests/cases/compiler/overrideKeywordEs5.ts b/tests/cases/compiler/overrideKeywordEs5.ts index c72dc83c55970..bb0411baa5612 100644 --- a/tests/cases/compiler/overrideKeywordEs5.ts +++ b/tests/cases/compiler/overrideKeywordEs5.ts @@ -101,6 +101,18 @@ class RejectWhenOverrideIsOnAParameter { public sayHello(override name: string) { return 'hi'; } } +// But can be be used on parameter properties + +abstract class AbstractPropertyBase { + abstract x: number; +} +class ConcretePropertyClass extends AbstractPropertyBase { + constructor(override x: number) { + super(); + } +} + + // Override is not used on class... override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } @@ -110,7 +122,7 @@ interface RejectWhenOverrideInAnInterface { override sayHello(name: string); } -/* @mhegazy: is this an appropriate test for consecutive declarations? */ +/* Override method should be grouped as consecutive declarations */ class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { override hasOwnProperty(prop: string): boolean { return super.hasOwnProperty(prop); diff --git a/tests/cases/fourslash/completionInJSDocFunctionNew.ts b/tests/cases/fourslash/completionInJSDocFunctionNew.ts index 6a06ec76fe5b9..742627974bdbf 100644 --- a/tests/cases/fourslash/completionInJSDocFunctionNew.ts +++ b/tests/cases/fourslash/completionInJSDocFunctionNew.ts @@ -6,5 +6,5 @@ ////var f = function () { return new/**/; } goTo.marker(); -verify.completionListCount(116); +verify.completionListCount(117); verify.completionListContains('new'); diff --git a/tests/cases/fourslash/completionInJSDocFunctionThis.ts b/tests/cases/fourslash/completionInJSDocFunctionThis.ts index 0fd771f272b46..237e50122966b 100644 --- a/tests/cases/fourslash/completionInJSDocFunctionThis.ts +++ b/tests/cases/fourslash/completionInJSDocFunctionThis.ts @@ -5,5 +5,5 @@ ////var f = function (s) { return this/**/; } goTo.marker(); -verify.completionListCount(117); +verify.completionListCount(118); verify.completionListContains('this') From 5fe3b4d4cb418bc79c54bace0140c1df79f65327 Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Sat, 2 Dec 2017 14:28:36 -0700 Subject: [PATCH 8/9] Accept new baselines --- src/compiler/commandLineParser.ts | 2 +- src/compiler/diagnosticMessages.json | 2 +- .../reference/api/tsserverlibrary.d.ts | 334 +++++++++-------- tests/baselines/reference/api/typescript.d.ts | 333 ++++++++-------- .../reference/noImplicitOverride.errors.txt | 203 +++++++--- .../baselines/reference/noImplicitOverride.js | 354 ++++++++++++++---- .../reference/noImplicitOverride.symbols | 250 +++++++++++++ .../reference/noImplicitOverride.types | 271 ++++++++++++++ .../reference/overrideKeywordEs5.errors.txt | 71 ++-- .../baselines/reference/overrideKeywordEs5.js | 78 ++-- .../reference/overrideKeywordEs5.symbols | 288 ++++++++++++++ .../reference/overrideKeywordEs5.types | 317 ++++++++++++++++ .../reference/overrideKeywordEs6.errors.txt | 3 +- .../baselines/reference/overrideKeywordEs6.js | 1 - .../reference/overrideKeywordEs6.symbols | 41 ++ .../reference/overrideKeywordEs6.types | 49 +++ .../Supports setting noImplicitOverride.js | 1 - .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + 25 files changed, 2101 insertions(+), 505 deletions(-) create mode 100644 tests/baselines/reference/noImplicitOverride.symbols create mode 100644 tests/baselines/reference/noImplicitOverride.types create mode 100644 tests/baselines/reference/overrideKeywordEs5.symbols create mode 100644 tests/baselines/reference/overrideKeywordEs5.types create mode 100644 tests/baselines/reference/overrideKeywordEs6.symbols create mode 100644 tests/baselines/reference/overrideKeywordEs6.types diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 7219d5e4984db..7b9a864d9c477 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -268,7 +268,7 @@ namespace ts { type: "boolean", showInSimplifiedHelpView: true, category: Diagnostics.Strict_Type_Checking_Options, - description: Diagnostics.Raise_an_error_when_inherited_Slashoverridden_class_members_are_not_explicitly_marked_override, + description: Diagnostics.Raise_error_when_inherited_Slashoverridden_class_members_are_not_explicitly_marked_override, }, { name: "strictNullChecks", diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 383d2d6c69721..f32cd77507bc0 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1972,7 +1972,7 @@ "category": "Error", "code": 2567 }, - "Raise an error when inherited/overridden class members are not explicitly marked 'override'": { + "Raise error when inherited/overridden class members are not explicitly marked 'override'": { "category": "Error", "code": 2568 }, diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 30c633c36d7ea..325c00dba95f9 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -203,160 +203,161 @@ declare namespace ts { UniqueKeyword = 140, FromKeyword = 141, GlobalKeyword = 142, - OfKeyword = 143, - QualifiedName = 144, - ComputedPropertyName = 145, - TypeParameter = 146, - Parameter = 147, - Decorator = 148, - PropertySignature = 149, - PropertyDeclaration = 150, - MethodSignature = 151, - MethodDeclaration = 152, - Constructor = 153, - GetAccessor = 154, - SetAccessor = 155, - CallSignature = 156, - ConstructSignature = 157, - IndexSignature = 158, - TypePredicate = 159, - TypeReference = 160, - FunctionType = 161, - ConstructorType = 162, - TypeQuery = 163, - TypeLiteral = 164, - ArrayType = 165, - TupleType = 166, - UnionType = 167, - IntersectionType = 168, - ParenthesizedType = 169, - ThisType = 170, - TypeOperator = 171, - IndexedAccessType = 172, - MappedType = 173, - LiteralType = 174, - ObjectBindingPattern = 175, - ArrayBindingPattern = 176, - BindingElement = 177, - ArrayLiteralExpression = 178, - ObjectLiteralExpression = 179, - PropertyAccessExpression = 180, - ElementAccessExpression = 181, - CallExpression = 182, - NewExpression = 183, - TaggedTemplateExpression = 184, - TypeAssertionExpression = 185, - ParenthesizedExpression = 186, - FunctionExpression = 187, - ArrowFunction = 188, - DeleteExpression = 189, - TypeOfExpression = 190, - VoidExpression = 191, - AwaitExpression = 192, - PrefixUnaryExpression = 193, - PostfixUnaryExpression = 194, - BinaryExpression = 195, - ConditionalExpression = 196, - TemplateExpression = 197, - YieldExpression = 198, - SpreadElement = 199, - ClassExpression = 200, - OmittedExpression = 201, - ExpressionWithTypeArguments = 202, - AsExpression = 203, - NonNullExpression = 204, - MetaProperty = 205, - TemplateSpan = 206, - SemicolonClassElement = 207, - Block = 208, - VariableStatement = 209, - EmptyStatement = 210, - ExpressionStatement = 211, - IfStatement = 212, - DoStatement = 213, - WhileStatement = 214, - ForStatement = 215, - ForInStatement = 216, - ForOfStatement = 217, - ContinueStatement = 218, - BreakStatement = 219, - ReturnStatement = 220, - WithStatement = 221, - SwitchStatement = 222, - LabeledStatement = 223, - ThrowStatement = 224, - TryStatement = 225, - DebuggerStatement = 226, - VariableDeclaration = 227, - VariableDeclarationList = 228, - FunctionDeclaration = 229, - ClassDeclaration = 230, - InterfaceDeclaration = 231, - TypeAliasDeclaration = 232, - EnumDeclaration = 233, - ModuleDeclaration = 234, - ModuleBlock = 235, - CaseBlock = 236, - NamespaceExportDeclaration = 237, - ImportEqualsDeclaration = 238, - ImportDeclaration = 239, - ImportClause = 240, - NamespaceImport = 241, - NamedImports = 242, - ImportSpecifier = 243, - ExportAssignment = 244, - ExportDeclaration = 245, - NamedExports = 246, - ExportSpecifier = 247, - MissingDeclaration = 248, - ExternalModuleReference = 249, - JsxElement = 250, - JsxSelfClosingElement = 251, - JsxOpeningElement = 252, - JsxClosingElement = 253, - JsxFragment = 254, - JsxOpeningFragment = 255, - JsxClosingFragment = 256, - JsxAttribute = 257, - JsxAttributes = 258, - JsxSpreadAttribute = 259, - JsxExpression = 260, - CaseClause = 261, - DefaultClause = 262, - HeritageClause = 263, - CatchClause = 264, - PropertyAssignment = 265, - ShorthandPropertyAssignment = 266, - SpreadAssignment = 267, - EnumMember = 268, - SourceFile = 269, - Bundle = 270, - JSDocTypeExpression = 271, - JSDocAllType = 272, - JSDocUnknownType = 273, - JSDocNullableType = 274, - JSDocNonNullableType = 275, - JSDocOptionalType = 276, - JSDocFunctionType = 277, - JSDocVariadicType = 278, - JSDocComment = 279, - JSDocTypeLiteral = 280, - JSDocTag = 281, - JSDocAugmentsTag = 282, - JSDocClassTag = 283, - JSDocParameterTag = 284, - JSDocReturnTag = 285, - JSDocTypeTag = 286, - JSDocTemplateTag = 287, - JSDocTypedefTag = 288, - JSDocPropertyTag = 289, - SyntaxList = 290, - NotEmittedStatement = 291, - PartiallyEmittedExpression = 292, - CommaListExpression = 293, - MergeDeclarationMarker = 294, - EndOfDeclarationMarker = 295, - Count = 296, + OverrideKeyword = 143, + OfKeyword = 144, + QualifiedName = 145, + ComputedPropertyName = 146, + TypeParameter = 147, + Parameter = 148, + Decorator = 149, + PropertySignature = 150, + PropertyDeclaration = 151, + MethodSignature = 152, + MethodDeclaration = 153, + Constructor = 154, + GetAccessor = 155, + SetAccessor = 156, + CallSignature = 157, + ConstructSignature = 158, + IndexSignature = 159, + TypePredicate = 160, + TypeReference = 161, + FunctionType = 162, + ConstructorType = 163, + TypeQuery = 164, + TypeLiteral = 165, + ArrayType = 166, + TupleType = 167, + UnionType = 168, + IntersectionType = 169, + ParenthesizedType = 170, + ThisType = 171, + TypeOperator = 172, + IndexedAccessType = 173, + MappedType = 174, + LiteralType = 175, + ObjectBindingPattern = 176, + ArrayBindingPattern = 177, + BindingElement = 178, + ArrayLiteralExpression = 179, + ObjectLiteralExpression = 180, + PropertyAccessExpression = 181, + ElementAccessExpression = 182, + CallExpression = 183, + NewExpression = 184, + TaggedTemplateExpression = 185, + TypeAssertionExpression = 186, + ParenthesizedExpression = 187, + FunctionExpression = 188, + ArrowFunction = 189, + DeleteExpression = 190, + TypeOfExpression = 191, + VoidExpression = 192, + AwaitExpression = 193, + PrefixUnaryExpression = 194, + PostfixUnaryExpression = 195, + BinaryExpression = 196, + ConditionalExpression = 197, + TemplateExpression = 198, + YieldExpression = 199, + SpreadElement = 200, + ClassExpression = 201, + OmittedExpression = 202, + ExpressionWithTypeArguments = 203, + AsExpression = 204, + NonNullExpression = 205, + MetaProperty = 206, + TemplateSpan = 207, + SemicolonClassElement = 208, + Block = 209, + VariableStatement = 210, + EmptyStatement = 211, + ExpressionStatement = 212, + IfStatement = 213, + DoStatement = 214, + WhileStatement = 215, + ForStatement = 216, + ForInStatement = 217, + ForOfStatement = 218, + ContinueStatement = 219, + BreakStatement = 220, + ReturnStatement = 221, + WithStatement = 222, + SwitchStatement = 223, + LabeledStatement = 224, + ThrowStatement = 225, + TryStatement = 226, + DebuggerStatement = 227, + VariableDeclaration = 228, + VariableDeclarationList = 229, + FunctionDeclaration = 230, + ClassDeclaration = 231, + InterfaceDeclaration = 232, + TypeAliasDeclaration = 233, + EnumDeclaration = 234, + ModuleDeclaration = 235, + ModuleBlock = 236, + CaseBlock = 237, + NamespaceExportDeclaration = 238, + ImportEqualsDeclaration = 239, + ImportDeclaration = 240, + ImportClause = 241, + NamespaceImport = 242, + NamedImports = 243, + ImportSpecifier = 244, + ExportAssignment = 245, + ExportDeclaration = 246, + NamedExports = 247, + ExportSpecifier = 248, + MissingDeclaration = 249, + ExternalModuleReference = 250, + JsxElement = 251, + JsxSelfClosingElement = 252, + JsxOpeningElement = 253, + JsxClosingElement = 254, + JsxFragment = 255, + JsxOpeningFragment = 256, + JsxClosingFragment = 257, + JsxAttribute = 258, + JsxAttributes = 259, + JsxSpreadAttribute = 260, + JsxExpression = 261, + CaseClause = 262, + DefaultClause = 263, + HeritageClause = 264, + CatchClause = 265, + PropertyAssignment = 266, + ShorthandPropertyAssignment = 267, + SpreadAssignment = 268, + EnumMember = 269, + SourceFile = 270, + Bundle = 271, + JSDocTypeExpression = 272, + JSDocAllType = 273, + JSDocUnknownType = 274, + JSDocNullableType = 275, + JSDocNonNullableType = 276, + JSDocOptionalType = 277, + JSDocFunctionType = 278, + JSDocVariadicType = 279, + JSDocComment = 280, + JSDocTypeLiteral = 281, + JSDocTag = 282, + JSDocAugmentsTag = 283, + JSDocClassTag = 284, + JSDocParameterTag = 285, + JSDocReturnTag = 286, + JSDocTypeTag = 287, + JSDocTemplateTag = 288, + JSDocTypedefTag = 289, + JSDocPropertyTag = 290, + SyntaxList = 291, + NotEmittedStatement = 292, + PartiallyEmittedExpression = 293, + CommaListExpression = 294, + MergeDeclarationMarker = 295, + EndOfDeclarationMarker = 296, + Count = 297, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -364,15 +365,15 @@ declare namespace ts { FirstReservedWord = 72, LastReservedWord = 107, FirstKeyword = 72, - LastKeyword = 143, + LastKeyword = 144, FirstFutureReservedWord = 108, LastFutureReservedWord = 116, - FirstTypeNode = 159, - LastTypeNode = 174, + FirstTypeNode = 160, + LastTypeNode = 175, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, - LastToken = 143, + LastToken = 144, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -381,11 +382,11 @@ declare namespace ts { LastTemplateToken = 16, FirstBinaryOperator = 27, LastBinaryOperator = 70, - FirstNode = 144, - FirstJSDocNode = 271, - LastJSDocNode = 289, - FirstJSDocTagNode = 281, - LastJSDocTagNode = 289, + FirstNode = 145, + FirstJSDocNode = 272, + LastJSDocNode = 290, + FirstJSDocTagNode = 282, + LastJSDocTagNode = 290, } enum NodeFlags { None = 0, @@ -427,12 +428,13 @@ declare namespace ts { Abstract = 128, Async = 256, Default = 512, + Override = 1024, Const = 2048, HasComputedFlags = 536870912, AccessibilityModifier = 28, ParameterPropertyModifier = 92, NonPublicAccessibilityModifier = 24, - TypeScriptModifier = 2270, + TypeScriptModifier = 3294, ExportDefault = 513, } enum JsxFlags { @@ -470,7 +472,7 @@ declare namespace ts { type AtToken = Token; type ReadonlyToken = Token; type AwaitKeywordToken = Token; - type Modifier = Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token; + type Modifier = Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token; type ModifiersArray = NodeArray; interface Identifier extends PrimaryExpression, Declaration { kind: SyntaxKind.Identifier; @@ -2263,6 +2265,7 @@ declare namespace ts { noEmitOnError?: boolean; noErrorTruncation?: boolean; noFallthroughCasesInSwitch?: boolean; + noImplicitOverride?: boolean; noImplicitAny?: boolean; noImplicitReturns?: boolean; noImplicitThis?: boolean; @@ -6856,6 +6859,7 @@ declare namespace ts.server.protocol { noErrorTruncation?: boolean; noFallthroughCasesInSwitch?: boolean; noImplicitAny?: boolean; + noImplicitOverride?: boolean; noImplicitReturns?: boolean; noImplicitThis?: boolean; noUnusedLocals?: boolean; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index fb6188c1891a7..7c53caab20c26 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -203,160 +203,161 @@ declare namespace ts { UniqueKeyword = 140, FromKeyword = 141, GlobalKeyword = 142, - OfKeyword = 143, - QualifiedName = 144, - ComputedPropertyName = 145, - TypeParameter = 146, - Parameter = 147, - Decorator = 148, - PropertySignature = 149, - PropertyDeclaration = 150, - MethodSignature = 151, - MethodDeclaration = 152, - Constructor = 153, - GetAccessor = 154, - SetAccessor = 155, - CallSignature = 156, - ConstructSignature = 157, - IndexSignature = 158, - TypePredicate = 159, - TypeReference = 160, - FunctionType = 161, - ConstructorType = 162, - TypeQuery = 163, - TypeLiteral = 164, - ArrayType = 165, - TupleType = 166, - UnionType = 167, - IntersectionType = 168, - ParenthesizedType = 169, - ThisType = 170, - TypeOperator = 171, - IndexedAccessType = 172, - MappedType = 173, - LiteralType = 174, - ObjectBindingPattern = 175, - ArrayBindingPattern = 176, - BindingElement = 177, - ArrayLiteralExpression = 178, - ObjectLiteralExpression = 179, - PropertyAccessExpression = 180, - ElementAccessExpression = 181, - CallExpression = 182, - NewExpression = 183, - TaggedTemplateExpression = 184, - TypeAssertionExpression = 185, - ParenthesizedExpression = 186, - FunctionExpression = 187, - ArrowFunction = 188, - DeleteExpression = 189, - TypeOfExpression = 190, - VoidExpression = 191, - AwaitExpression = 192, - PrefixUnaryExpression = 193, - PostfixUnaryExpression = 194, - BinaryExpression = 195, - ConditionalExpression = 196, - TemplateExpression = 197, - YieldExpression = 198, - SpreadElement = 199, - ClassExpression = 200, - OmittedExpression = 201, - ExpressionWithTypeArguments = 202, - AsExpression = 203, - NonNullExpression = 204, - MetaProperty = 205, - TemplateSpan = 206, - SemicolonClassElement = 207, - Block = 208, - VariableStatement = 209, - EmptyStatement = 210, - ExpressionStatement = 211, - IfStatement = 212, - DoStatement = 213, - WhileStatement = 214, - ForStatement = 215, - ForInStatement = 216, - ForOfStatement = 217, - ContinueStatement = 218, - BreakStatement = 219, - ReturnStatement = 220, - WithStatement = 221, - SwitchStatement = 222, - LabeledStatement = 223, - ThrowStatement = 224, - TryStatement = 225, - DebuggerStatement = 226, - VariableDeclaration = 227, - VariableDeclarationList = 228, - FunctionDeclaration = 229, - ClassDeclaration = 230, - InterfaceDeclaration = 231, - TypeAliasDeclaration = 232, - EnumDeclaration = 233, - ModuleDeclaration = 234, - ModuleBlock = 235, - CaseBlock = 236, - NamespaceExportDeclaration = 237, - ImportEqualsDeclaration = 238, - ImportDeclaration = 239, - ImportClause = 240, - NamespaceImport = 241, - NamedImports = 242, - ImportSpecifier = 243, - ExportAssignment = 244, - ExportDeclaration = 245, - NamedExports = 246, - ExportSpecifier = 247, - MissingDeclaration = 248, - ExternalModuleReference = 249, - JsxElement = 250, - JsxSelfClosingElement = 251, - JsxOpeningElement = 252, - JsxClosingElement = 253, - JsxFragment = 254, - JsxOpeningFragment = 255, - JsxClosingFragment = 256, - JsxAttribute = 257, - JsxAttributes = 258, - JsxSpreadAttribute = 259, - JsxExpression = 260, - CaseClause = 261, - DefaultClause = 262, - HeritageClause = 263, - CatchClause = 264, - PropertyAssignment = 265, - ShorthandPropertyAssignment = 266, - SpreadAssignment = 267, - EnumMember = 268, - SourceFile = 269, - Bundle = 270, - JSDocTypeExpression = 271, - JSDocAllType = 272, - JSDocUnknownType = 273, - JSDocNullableType = 274, - JSDocNonNullableType = 275, - JSDocOptionalType = 276, - JSDocFunctionType = 277, - JSDocVariadicType = 278, - JSDocComment = 279, - JSDocTypeLiteral = 280, - JSDocTag = 281, - JSDocAugmentsTag = 282, - JSDocClassTag = 283, - JSDocParameterTag = 284, - JSDocReturnTag = 285, - JSDocTypeTag = 286, - JSDocTemplateTag = 287, - JSDocTypedefTag = 288, - JSDocPropertyTag = 289, - SyntaxList = 290, - NotEmittedStatement = 291, - PartiallyEmittedExpression = 292, - CommaListExpression = 293, - MergeDeclarationMarker = 294, - EndOfDeclarationMarker = 295, - Count = 296, + OverrideKeyword = 143, + OfKeyword = 144, + QualifiedName = 145, + ComputedPropertyName = 146, + TypeParameter = 147, + Parameter = 148, + Decorator = 149, + PropertySignature = 150, + PropertyDeclaration = 151, + MethodSignature = 152, + MethodDeclaration = 153, + Constructor = 154, + GetAccessor = 155, + SetAccessor = 156, + CallSignature = 157, + ConstructSignature = 158, + IndexSignature = 159, + TypePredicate = 160, + TypeReference = 161, + FunctionType = 162, + ConstructorType = 163, + TypeQuery = 164, + TypeLiteral = 165, + ArrayType = 166, + TupleType = 167, + UnionType = 168, + IntersectionType = 169, + ParenthesizedType = 170, + ThisType = 171, + TypeOperator = 172, + IndexedAccessType = 173, + MappedType = 174, + LiteralType = 175, + ObjectBindingPattern = 176, + ArrayBindingPattern = 177, + BindingElement = 178, + ArrayLiteralExpression = 179, + ObjectLiteralExpression = 180, + PropertyAccessExpression = 181, + ElementAccessExpression = 182, + CallExpression = 183, + NewExpression = 184, + TaggedTemplateExpression = 185, + TypeAssertionExpression = 186, + ParenthesizedExpression = 187, + FunctionExpression = 188, + ArrowFunction = 189, + DeleteExpression = 190, + TypeOfExpression = 191, + VoidExpression = 192, + AwaitExpression = 193, + PrefixUnaryExpression = 194, + PostfixUnaryExpression = 195, + BinaryExpression = 196, + ConditionalExpression = 197, + TemplateExpression = 198, + YieldExpression = 199, + SpreadElement = 200, + ClassExpression = 201, + OmittedExpression = 202, + ExpressionWithTypeArguments = 203, + AsExpression = 204, + NonNullExpression = 205, + MetaProperty = 206, + TemplateSpan = 207, + SemicolonClassElement = 208, + Block = 209, + VariableStatement = 210, + EmptyStatement = 211, + ExpressionStatement = 212, + IfStatement = 213, + DoStatement = 214, + WhileStatement = 215, + ForStatement = 216, + ForInStatement = 217, + ForOfStatement = 218, + ContinueStatement = 219, + BreakStatement = 220, + ReturnStatement = 221, + WithStatement = 222, + SwitchStatement = 223, + LabeledStatement = 224, + ThrowStatement = 225, + TryStatement = 226, + DebuggerStatement = 227, + VariableDeclaration = 228, + VariableDeclarationList = 229, + FunctionDeclaration = 230, + ClassDeclaration = 231, + InterfaceDeclaration = 232, + TypeAliasDeclaration = 233, + EnumDeclaration = 234, + ModuleDeclaration = 235, + ModuleBlock = 236, + CaseBlock = 237, + NamespaceExportDeclaration = 238, + ImportEqualsDeclaration = 239, + ImportDeclaration = 240, + ImportClause = 241, + NamespaceImport = 242, + NamedImports = 243, + ImportSpecifier = 244, + ExportAssignment = 245, + ExportDeclaration = 246, + NamedExports = 247, + ExportSpecifier = 248, + MissingDeclaration = 249, + ExternalModuleReference = 250, + JsxElement = 251, + JsxSelfClosingElement = 252, + JsxOpeningElement = 253, + JsxClosingElement = 254, + JsxFragment = 255, + JsxOpeningFragment = 256, + JsxClosingFragment = 257, + JsxAttribute = 258, + JsxAttributes = 259, + JsxSpreadAttribute = 260, + JsxExpression = 261, + CaseClause = 262, + DefaultClause = 263, + HeritageClause = 264, + CatchClause = 265, + PropertyAssignment = 266, + ShorthandPropertyAssignment = 267, + SpreadAssignment = 268, + EnumMember = 269, + SourceFile = 270, + Bundle = 271, + JSDocTypeExpression = 272, + JSDocAllType = 273, + JSDocUnknownType = 274, + JSDocNullableType = 275, + JSDocNonNullableType = 276, + JSDocOptionalType = 277, + JSDocFunctionType = 278, + JSDocVariadicType = 279, + JSDocComment = 280, + JSDocTypeLiteral = 281, + JSDocTag = 282, + JSDocAugmentsTag = 283, + JSDocClassTag = 284, + JSDocParameterTag = 285, + JSDocReturnTag = 286, + JSDocTypeTag = 287, + JSDocTemplateTag = 288, + JSDocTypedefTag = 289, + JSDocPropertyTag = 290, + SyntaxList = 291, + NotEmittedStatement = 292, + PartiallyEmittedExpression = 293, + CommaListExpression = 294, + MergeDeclarationMarker = 295, + EndOfDeclarationMarker = 296, + Count = 297, FirstAssignment = 58, LastAssignment = 70, FirstCompoundAssignment = 59, @@ -364,15 +365,15 @@ declare namespace ts { FirstReservedWord = 72, LastReservedWord = 107, FirstKeyword = 72, - LastKeyword = 143, + LastKeyword = 144, FirstFutureReservedWord = 108, LastFutureReservedWord = 116, - FirstTypeNode = 159, - LastTypeNode = 174, + FirstTypeNode = 160, + LastTypeNode = 175, FirstPunctuation = 17, LastPunctuation = 70, FirstToken = 0, - LastToken = 143, + LastToken = 144, FirstTriviaToken = 2, LastTriviaToken = 7, FirstLiteralToken = 8, @@ -381,11 +382,11 @@ declare namespace ts { LastTemplateToken = 16, FirstBinaryOperator = 27, LastBinaryOperator = 70, - FirstNode = 144, - FirstJSDocNode = 271, - LastJSDocNode = 289, - FirstJSDocTagNode = 281, - LastJSDocTagNode = 289, + FirstNode = 145, + FirstJSDocNode = 272, + LastJSDocNode = 290, + FirstJSDocTagNode = 282, + LastJSDocTagNode = 290, } enum NodeFlags { None = 0, @@ -427,12 +428,13 @@ declare namespace ts { Abstract = 128, Async = 256, Default = 512, + Override = 1024, Const = 2048, HasComputedFlags = 536870912, AccessibilityModifier = 28, ParameterPropertyModifier = 92, NonPublicAccessibilityModifier = 24, - TypeScriptModifier = 2270, + TypeScriptModifier = 3294, ExportDefault = 513, } enum JsxFlags { @@ -470,7 +472,7 @@ declare namespace ts { type AtToken = Token; type ReadonlyToken = Token; type AwaitKeywordToken = Token; - type Modifier = Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token; + type Modifier = Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token | Token; type ModifiersArray = NodeArray; interface Identifier extends PrimaryExpression, Declaration { kind: SyntaxKind.Identifier; @@ -2263,6 +2265,7 @@ declare namespace ts { noEmitOnError?: boolean; noErrorTruncation?: boolean; noFallthroughCasesInSwitch?: boolean; + noImplicitOverride?: boolean; noImplicitAny?: boolean; noImplicitReturns?: boolean; noImplicitThis?: boolean; diff --git a/tests/baselines/reference/noImplicitOverride.errors.txt b/tests/baselines/reference/noImplicitOverride.errors.txt index 4296d22cd732f..8b878df018efd 100644 --- a/tests/baselines/reference/noImplicitOverride.errors.txt +++ b/tests/baselines/reference/noImplicitOverride.errors.txt @@ -1,86 +1,193 @@ -tests/cases/compiler/noImplicitOverride.ts(11,5): error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) -tests/cases/compiler/noImplicitOverride.ts(12,5): error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) -tests/cases/compiler/noImplicitOverride.ts(18,5): error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.toString) -tests/cases/compiler/noImplicitOverride.ts(19,5): error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) -tests/cases/compiler/noImplicitOverride.ts(25,5): error TS2322: Type '(prop: string) => number' is not assignable to type '(v: string) => boolean'. - Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) -tests/cases/compiler/noImplicitOverride.ts(31,12): error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) -tests/cases/compiler/noImplicitOverride.ts(35,9): error TS90034: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) -tests/cases/compiler/noImplicitOverride.ts(43,5): error TS1070: 'override' modifier cannot appear on a type member. -tests/cases/compiler/noImplicitOverride.ts(52,29): error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) +tests/cases/compiler/noImplicitOverride.ts(5,7): error TS2300: Duplicate identifier 'RejectWhenOverrideAbsentOnInheritedMethod'. +tests/cases/compiler/noImplicitOverride.ts(6,5): error TS2570: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +tests/cases/compiler/noImplicitOverride.ts(8,7): error TS2300: Duplicate identifier 'AcceptWhenOverridePresentOnInheritedMethod'. +tests/cases/compiler/noImplicitOverride.ts(14,5): error TS2570: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +tests/cases/compiler/noImplicitOverride.ts(23,5): error TS2322: Type '() => number' is not assignable to type '() => string'. + Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) +tests/cases/compiler/noImplicitOverride.ts(45,12): error TS2570: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/noImplicitOverride.ts(52,9): error TS2570: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/noImplicitOverride.ts(58,7): error TS2300: Duplicate identifier 'RejectWhenOverrideAbsentOnInheritedMethod'. +tests/cases/compiler/noImplicitOverride.ts(59,5): error TS2570: Class member 'getMeaningOfLife' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) +tests/cases/compiler/noImplicitOverride.ts(61,7): error TS2300: Duplicate identifier 'AcceptWhenOverridePresentOnInheritedMethod'. +tests/cases/compiler/noImplicitOverride.ts(65,7): error TS2415: Class 'RejectWhenOverridePresentWithPrivateModifier' incorrectly extends base class 'Base'. + Types have separate declarations of a private property 'processInternal'. +tests/cases/compiler/noImplicitOverride.ts(66,13): error TS1243: 'private' modifier cannot be used with 'override' modifier. +tests/cases/compiler/noImplicitOverride.ts(79,5): error TS1070: 'override' modifier cannot appear on a type member. +tests/cases/compiler/noImplicitOverride.ts(102,14): error TS1243: 'abstract' modifier cannot be used with 'override' modifier. +tests/cases/compiler/noImplicitOverride.ts(122,5): error TS2570: Class member 'normal' must be marked 'override' when noImplicitOverride is enabled (inherited from .(Anonymous class) & A) +tests/cases/compiler/noImplicitOverride.ts(123,5): error TS2570: Class member 'mixedIn' must be marked 'override' when noImplicitOverride is enabled (inherited from .(Anonymous class) & A) -==== tests/cases/compiler/noImplicitOverride.ts (9 errors) ==== +==== tests/cases/compiler/noImplicitOverride.ts (16 errors) ==== + // ****************************************************** + // First set of cases deal with inheritance from Object. + // ****************************************************** - class Base { - get name(): string { - return 'Base'; - } - getMeaningOfLife(): number { return 42; } - public userId: number = 1; - } - - class RejectWhenOverrideMissingOnInheritedMethod extends Object { + class RejectWhenOverrideAbsentOnInheritedMethod extends Object { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2300: Duplicate identifier 'RejectWhenOverrideAbsentOnInheritedMethod'. toString(): string { return 'foo'; }; ~~~~~~~~ -!!! error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) - hasOwnProperty(prop: string): boolean { - ~~~~~~~~~~~~~~ -!!! error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Object) - return super.hasOwnProperty(prop); - } +!!! error TS2570: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) + } + class AcceptWhenOverridePresentOnInheritedMethod extends Object { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2300: Duplicate identifier 'AcceptWhenOverridePresentOnInheritedMethod'. + override toString(): string { return 'foo'; }; } - class RejectWhenOverrideMissingOnAugmentedProperty { + // Similar to previous cases where augmentation from Object is implicit + class RejectWhenOverrideAbsentOnAugmentedProperty { toString(): string { return 'foo'; }; ~~~~~~~~ -!!! error TS90034: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.toString) - hasOwnProperty(prop: string): boolean { - ~~~~~~~~~~~~~~ -!!! error TS90034: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) - return false; - } +!!! error TS2570: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) + } + class AcceptWhenOverridePresentOnAugumentedProperty extends Object { + override toString(): string { return 'foo'; }; } + // This should fail via type mismatch of the return value. + // (test is not specific to the override checking code) class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { - hasOwnProperty(prop: string): number { - ~~~~~~~~~~~~~~ -!!! error TS2322: Type '(prop: string) => number' is not assignable to type '(v: string) => boolean'. -!!! error TS2322: Class member 'hasOwnProperty' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.hasOwnProperty) + toString(): number { + ~~~~~~~~ +!!! error TS2322: Type '() => number' is not assignable to type '() => string'. +!!! error TS2322: Class member 'toString' must be marked 'override' when noImplicitOverride is enabled (inherited from Object) return -1; } } - class RejectWhenOverrideMissingOnInheritedProperty extends Base { + // ****************************************************** + // Next set of cases deal with inheritance derived from + // an explicitly defined class. + // ****************************************************** + + class Base { + // Public property + public userId: number = 1; + // Accessor + get name(): string { return 'Base'; } + // Typical public method + getMeaningOfLife(): number { return 42; } + // Private method + private processInternal(): void { } + } + + class RejectWhenOverrideAbsentOnInheritedProperty extends Base { public userId = 2; ~~~~~~ -!!! error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) +!!! error TS2570: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + } + class AcceptWhenOverridePresentOnInheritedProperty extends Base { + public override userId = 2; } - class RejectWhenOverrideMissingOnInheritedAccessor extends Base { + class RejectWhenOverrideAbsentOnInheritedAccessor extends Base { get name(): string { return 'foo'; }; ~~~~ -!!! error TS90034: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) +!!! error TS2570: Class member 'name' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + } + class AcceptWhenOverridePresentOnInheritedAccessor extends Base { + override get name(): string { return 'foo'; }; + } + + class RejectWhenOverrideAbsentOnInheritedMethod extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2300: Duplicate identifier 'RejectWhenOverrideAbsentOnInheritedMethod'. + getMeaningOfLife(): number { return 24; }; + ~~~~~~~~~~~~~~~~ +!!! error TS2570: Class member 'getMeaningOfLife' must be marked 'override' when noImplicitOverride is enabled (inherited from Base) + } + class AcceptWhenOverridePresentOnInheritedMethod extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2300: Duplicate identifier 'AcceptWhenOverridePresentOnInheritedMethod'. + override getMeaningOfLife(): number { return 24; }; } + class RejectWhenOverridePresentWithPrivateModifier extends Base { + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2415: Class 'RejectWhenOverridePresentWithPrivateModifier' incorrectly extends base class 'Base'. +!!! error TS2415: Types have separate declarations of a private property 'processInternal'. + private override processInternal() { } + ~~~~~~~~ +!!! error TS1243: 'private' modifier cannot be used with 'override' modifier. + } + + // ****************************************************** + // Next set of cases deal with override within interfaces + // and abstract classes (where is should not be present). + // ****************************************************** + interface Shape { getWidth(): number; } - interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape { + interface RejectWhenOverridePresentOnInterfaceDeclaration extends Shape { override getWidth(): number; ~~~~~~~~ !!! error TS1070: 'override' modifier cannot appear on a type member. } - interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape { - // abstract members don't need to be declared override + interface AcceptWhenOverrideAbsentOnInterfaceDeclaration extends Shape { getWidth(): number; } - class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { - /** @override */ public userId: number = 2; - ~~~~~~ -!!! error TS90034: Class member 'userId' must be marked 'override' when noImplicitOverride is enabled (augmented from Object.Base) + // ****************************************************** + // Next set of cases deal with override with abstract + // classes. + // ****************************************************** + + abstract class Animal { + protected readonly name: string + + constructor(name: string) { + this.name = name; + } + + abstract speak(): string; + } + + abstract class RejectWhenOverridePresentWithAbstractModifier extends Animal { + abstract override speak(): string; + ~~~~~~~~ +!!! error TS1243: 'abstract' modifier cannot be used with 'override' modifier. + } + + abstract class AcceptWhenOverridePresentOnConcreteDeclaration extends Animal { + override speak(): string { return "Woof!"; } } + + // ****************************************************** + // Next set of cases deal with override with mixins + // ****************************************************** + + const mixin = {}>(Base: BC) => class extends Base { + mixedIn() {} + }; + + class A { + normal() {} + } + + class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(A) { + normal() {} + ~~~~~~ +!!! error TS2570: Class member 'normal' must be marked 'override' when noImplicitOverride is enabled (inherited from .(Anonymous class) & A) + mixedIn() {} + ~~~~~~~ +!!! error TS2570: Class member 'mixedIn' must be marked 'override' when noImplicitOverride is enabled (inherited from .(Anonymous class) & A) + } + + class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(A) { + override normal() {} + override mixedIn() {} + } + + // ******************************************************** + // Next set of cases deal with override specified via JsDoc + // ******************************************************** + + //class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { + // /** @override */ public speak(): string { return "Woof!" } + //} \ No newline at end of file diff --git a/tests/baselines/reference/noImplicitOverride.js b/tests/baselines/reference/noImplicitOverride.js index dba3cecbe7a44..60a3ed5478ac9 100644 --- a/tests/baselines/reference/noImplicitOverride.js +++ b/tests/baselines/reference/noImplicitOverride.js @@ -1,60 +1,147 @@ //// [noImplicitOverride.ts] +// ****************************************************** +// First set of cases deal with inheritance from Object. +// ****************************************************** -class Base { - get name(): string { - return 'Base'; - } - getMeaningOfLife(): number { return 42; } - public userId: number = 1; -} - -class RejectWhenOverrideMissingOnInheritedMethod extends Object { +class RejectWhenOverrideAbsentOnInheritedMethod extends Object { toString(): string { return 'foo'; }; - hasOwnProperty(prop: string): boolean { - return super.hasOwnProperty(prop); - } +} +class AcceptWhenOverridePresentOnInheritedMethod extends Object { + override toString(): string { return 'foo'; }; } -class RejectWhenOverrideMissingOnAugmentedProperty { +// Similar to previous cases where augmentation from Object is implicit +class RejectWhenOverrideAbsentOnAugmentedProperty { toString(): string { return 'foo'; }; - hasOwnProperty(prop: string): boolean { - return false; - } +} +class AcceptWhenOverridePresentOnAugumentedProperty extends Object { + override toString(): string { return 'foo'; }; } +// This should fail via type mismatch of the return value. +// (test is not specific to the override checking code) class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { - hasOwnProperty(prop: string): number { + toString(): number { return -1; } } -class RejectWhenOverrideMissingOnInheritedProperty extends Base { +// ****************************************************** +// Next set of cases deal with inheritance derived from +// an explicitly defined class. +// ****************************************************** + +class Base { + // Public property + public userId: number = 1; + // Accessor + get name(): string { return 'Base'; } + // Typical public method + getMeaningOfLife(): number { return 42; } + // Private method + private processInternal(): void { } +} + +class RejectWhenOverrideAbsentOnInheritedProperty extends Base { public userId = 2; } +class AcceptWhenOverridePresentOnInheritedProperty extends Base { + public override userId = 2; +} -class RejectWhenOverrideMissingOnInheritedAccessor extends Base { +class RejectWhenOverrideAbsentOnInheritedAccessor extends Base { get name(): string { return 'foo'; }; } +class AcceptWhenOverridePresentOnInheritedAccessor extends Base { + override get name(): string { return 'foo'; }; +} + +class RejectWhenOverrideAbsentOnInheritedMethod extends Base { + getMeaningOfLife(): number { return 24; }; +} +class AcceptWhenOverridePresentOnInheritedMethod extends Base { + override getMeaningOfLife(): number { return 24; }; +} + +class RejectWhenOverridePresentWithPrivateModifier extends Base { + private override processInternal() { } +} + +// ****************************************************** +// Next set of cases deal with override within interfaces +// and abstract classes (where is should not be present). +// ****************************************************** interface Shape { getWidth(): number; } -interface RejectWhenOverrideOnAbstractDeclaration_Line extends Shape { +interface RejectWhenOverridePresentOnInterfaceDeclaration extends Shape { override getWidth(): number; } -interface AcceptWhenOverrideNotOnAbstractDeclaration_Line extends Shape { - // abstract members don't need to be declared override +interface AcceptWhenOverrideAbsentOnInterfaceDeclaration extends Shape { getWidth(): number; } -class FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Base { - /** @override */ public userId: number = 2; +// ****************************************************** +// Next set of cases deal with override with abstract +// classes. +// ****************************************************** + +abstract class Animal { + protected readonly name: string + + constructor(name: string) { + this.name = name; + } + + abstract speak(): string; +} + +abstract class RejectWhenOverridePresentWithAbstractModifier extends Animal { + abstract override speak(): string; +} + +abstract class AcceptWhenOverridePresentOnConcreteDeclaration extends Animal { + override speak(): string { return "Woof!"; } +} + +// ****************************************************** +// Next set of cases deal with override with mixins +// ****************************************************** + +const mixin = {}>(Base: BC) => class extends Base { + mixedIn() {} +}; + +class A { + normal() {} +} + +class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(A) { + normal() {} + mixedIn() {} } + +class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(A) { + override normal() {} + override mixedIn() {} +} + +// ******************************************************** +// Next set of cases deal with override specified via JsDoc +// ******************************************************** + +//class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { +// /** @override */ public speak(): string { return "Woof!" } +//} //// [noImplicitOverride.js] +// ****************************************************** +// First set of cases deal with inheritance from Object. +// ****************************************************** var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || @@ -65,78 +152,205 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); -var Base = (function () { - function Base() { - this.userId = 1; +var RejectWhenOverrideAbsentOnInheritedMethod = /** @class */ (function (_super) { + __extends(RejectWhenOverrideAbsentOnInheritedMethod, _super); + function RejectWhenOverrideAbsentOnInheritedMethod() { + return _super !== null && _super.apply(this, arguments) || this; } - Object.defineProperty(Base.prototype, "name", { - get: function () { - return 'Base'; - }, - enumerable: true, - configurable: true - }); - Base.prototype.getMeaningOfLife = function () { return 42; }; - return Base; -}()); -var RejectWhenOverrideMissingOnInheritedMethod = (function (_super) { - __extends(RejectWhenOverrideMissingOnInheritedMethod, _super); - function RejectWhenOverrideMissingOnInheritedMethod() { + RejectWhenOverrideAbsentOnInheritedMethod.prototype.toString = function () { return 'foo'; }; + ; + return RejectWhenOverrideAbsentOnInheritedMethod; +}(Object)); +var AcceptWhenOverridePresentOnInheritedMethod = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnInheritedMethod, _super); + function AcceptWhenOverridePresentOnInheritedMethod() { return _super !== null && _super.apply(this, arguments) || this; } - RejectWhenOverrideMissingOnInheritedMethod.prototype.toString = function () { return 'foo'; }; + AcceptWhenOverridePresentOnInheritedMethod.prototype.toString = function () { return 'foo'; }; ; - RejectWhenOverrideMissingOnInheritedMethod.prototype.hasOwnProperty = function (prop) { - return _super.prototype.hasOwnProperty.call(this, prop); - }; - return RejectWhenOverrideMissingOnInheritedMethod; + return AcceptWhenOverridePresentOnInheritedMethod; }(Object)); -var RejectWhenOverrideMissingOnAugmentedProperty = (function () { - function RejectWhenOverrideMissingOnAugmentedProperty() { +// Similar to previous cases where augmentation from Object is implicit +var RejectWhenOverrideAbsentOnAugmentedProperty = /** @class */ (function () { + function RejectWhenOverrideAbsentOnAugmentedProperty() { } - RejectWhenOverrideMissingOnAugmentedProperty.prototype.toString = function () { return 'foo'; }; + RejectWhenOverrideAbsentOnAugmentedProperty.prototype.toString = function () { return 'foo'; }; ; - RejectWhenOverrideMissingOnAugmentedProperty.prototype.hasOwnProperty = function (prop) { - return false; - }; - return RejectWhenOverrideMissingOnAugmentedProperty; + return RejectWhenOverrideAbsentOnAugmentedProperty; }()); -var RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember = (function () { +var AcceptWhenOverridePresentOnAugumentedProperty = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnAugumentedProperty, _super); + function AcceptWhenOverridePresentOnAugumentedProperty() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverridePresentOnAugumentedProperty.prototype.toString = function () { return 'foo'; }; + ; + return AcceptWhenOverridePresentOnAugumentedProperty; +}(Object)); +// This should fail via type mismatch of the return value. +// (test is not specific to the override checking code) +var RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember = /** @class */ (function () { function RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember() { } - RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember.prototype.hasOwnProperty = function (prop) { + RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember.prototype.toString = function () { return -1; }; return RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember; }()); -var RejectWhenOverrideMissingOnInheritedProperty = (function (_super) { - __extends(RejectWhenOverrideMissingOnInheritedProperty, _super); - function RejectWhenOverrideMissingOnInheritedProperty() { +// ****************************************************** +// Next set of cases deal with inheritance derived from +// an explicitly defined class. +// ****************************************************** +var Base = /** @class */ (function () { + function Base() { + // Public property + this.userId = 1; + } + Object.defineProperty(Base.prototype, "name", { + // Accessor + get: function () { return 'Base'; }, + enumerable: true, + configurable: true + }); + // Typical public method + Base.prototype.getMeaningOfLife = function () { return 42; }; + // Private method + Base.prototype.processInternal = function () { }; + return Base; +}()); +var RejectWhenOverrideAbsentOnInheritedProperty = /** @class */ (function (_super) { + __extends(RejectWhenOverrideAbsentOnInheritedProperty, _super); + function RejectWhenOverrideAbsentOnInheritedProperty() { + var _this = _super !== null && _super.apply(this, arguments) || this; + _this.userId = 2; + return _this; + } + return RejectWhenOverrideAbsentOnInheritedProperty; +}(Base)); +var AcceptWhenOverridePresentOnInheritedProperty = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnInheritedProperty, _super); + function AcceptWhenOverridePresentOnInheritedProperty() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.userId = 2; return _this; } - return RejectWhenOverrideMissingOnInheritedProperty; + return AcceptWhenOverridePresentOnInheritedProperty; }(Base)); -var RejectWhenOverrideMissingOnInheritedAccessor = (function (_super) { - __extends(RejectWhenOverrideMissingOnInheritedAccessor, _super); - function RejectWhenOverrideMissingOnInheritedAccessor() { +var RejectWhenOverrideAbsentOnInheritedAccessor = /** @class */ (function (_super) { + __extends(RejectWhenOverrideAbsentOnInheritedAccessor, _super); + function RejectWhenOverrideAbsentOnInheritedAccessor() { return _super !== null && _super.apply(this, arguments) || this; } - Object.defineProperty(RejectWhenOverrideMissingOnInheritedAccessor.prototype, "name", { + Object.defineProperty(RejectWhenOverrideAbsentOnInheritedAccessor.prototype, "name", { get: function () { return 'foo'; }, enumerable: true, configurable: true }); ; - return RejectWhenOverrideMissingOnInheritedAccessor; + return RejectWhenOverrideAbsentOnInheritedAccessor; }(Base)); -var FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation = (function (_super) { - __extends(FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation, _super); - function FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation() { - var _this = _super !== null && _super.apply(this, arguments) || this; - /** @override */ _this.userId = 2; - return _this; +var AcceptWhenOverridePresentOnInheritedAccessor = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnInheritedAccessor, _super); + function AcceptWhenOverridePresentOnInheritedAccessor() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(AcceptWhenOverridePresentOnInheritedAccessor.prototype, "name", { + get: function () { return 'foo'; }, + enumerable: true, + configurable: true + }); + ; + return AcceptWhenOverridePresentOnInheritedAccessor; +}(Base)); +var RejectWhenOverrideAbsentOnInheritedMethod = /** @class */ (function (_super) { + __extends(RejectWhenOverrideAbsentOnInheritedMethod, _super); + function RejectWhenOverrideAbsentOnInheritedMethod() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideAbsentOnInheritedMethod.prototype.getMeaningOfLife = function () { return 24; }; + ; + return RejectWhenOverrideAbsentOnInheritedMethod; +}(Base)); +var AcceptWhenOverridePresentOnInheritedMethod = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnInheritedMethod, _super); + function AcceptWhenOverridePresentOnInheritedMethod() { + return _super !== null && _super.apply(this, arguments) || this; } - return FIXME_AcceptWhenOverrideSpecifiedByJSDocAnnotation; + AcceptWhenOverridePresentOnInheritedMethod.prototype.getMeaningOfLife = function () { return 24; }; + ; + return AcceptWhenOverridePresentOnInheritedMethod; }(Base)); +var RejectWhenOverridePresentWithPrivateModifier = /** @class */ (function (_super) { + __extends(RejectWhenOverridePresentWithPrivateModifier, _super); + function RejectWhenOverridePresentWithPrivateModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverridePresentWithPrivateModifier.prototype.processInternal = function () { }; + return RejectWhenOverridePresentWithPrivateModifier; +}(Base)); +// ****************************************************** +// Next set of cases deal with override with abstract +// classes. +// ****************************************************** +var Animal = /** @class */ (function () { + function Animal(name) { + this.name = name; + } + return Animal; +}()); +var RejectWhenOverridePresentWithAbstractModifier = /** @class */ (function (_super) { + __extends(RejectWhenOverridePresentWithAbstractModifier, _super); + function RejectWhenOverridePresentWithAbstractModifier() { + return _super !== null && _super.apply(this, arguments) || this; + } + return RejectWhenOverridePresentWithAbstractModifier; +}(Animal)); +var AcceptWhenOverridePresentOnConcreteDeclaration = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnConcreteDeclaration, _super); + function AcceptWhenOverridePresentOnConcreteDeclaration() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverridePresentOnConcreteDeclaration.prototype.speak = function () { return "Woof!"; }; + return AcceptWhenOverridePresentOnConcreteDeclaration; +}(Animal)); +// ****************************************************** +// Next set of cases deal with override with mixins +// ****************************************************** +var mixin = function (Base) { return /** @class */ (function (_super) { + __extends(class_1, _super); + function class_1() { + return _super !== null && _super.apply(this, arguments) || this; + } + class_1.prototype.mixedIn = function () { }; + return class_1; +}(Base)); }; +var A = /** @class */ (function () { + function A() { + } + A.prototype.normal = function () { }; + return A; +}()); +var RejectWhenOverrideAbsentOnInheritedMethodMixin = /** @class */ (function (_super) { + __extends(RejectWhenOverrideAbsentOnInheritedMethodMixin, _super); + function RejectWhenOverrideAbsentOnInheritedMethodMixin() { + return _super !== null && _super.apply(this, arguments) || this; + } + RejectWhenOverrideAbsentOnInheritedMethodMixin.prototype.normal = function () { }; + RejectWhenOverrideAbsentOnInheritedMethodMixin.prototype.mixedIn = function () { }; + return RejectWhenOverrideAbsentOnInheritedMethodMixin; +}(mixin(A))); +var AcceptWhenOverridePresentOnInheritedMethodMixin = /** @class */ (function (_super) { + __extends(AcceptWhenOverridePresentOnInheritedMethodMixin, _super); + function AcceptWhenOverridePresentOnInheritedMethodMixin() { + return _super !== null && _super.apply(this, arguments) || this; + } + AcceptWhenOverridePresentOnInheritedMethodMixin.prototype.normal = function () { }; + AcceptWhenOverridePresentOnInheritedMethodMixin.prototype.mixedIn = function () { }; + return AcceptWhenOverridePresentOnInheritedMethodMixin; +}(mixin(A))); +// ******************************************************** +// Next set of cases deal with override specified via JsDoc +// ******************************************************** +//class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { +// /** @override */ public speak(): string { return "Woof!" } +//} diff --git a/tests/baselines/reference/noImplicitOverride.symbols b/tests/baselines/reference/noImplicitOverride.symbols new file mode 100644 index 0000000000000..80fa4ad3ce197 --- /dev/null +++ b/tests/baselines/reference/noImplicitOverride.symbols @@ -0,0 +1,250 @@ +=== tests/cases/compiler/noImplicitOverride.ts === +// ****************************************************** +// First set of cases deal with inheritance from Object. +// ****************************************************** + +class RejectWhenOverrideAbsentOnInheritedMethod extends Object { +>RejectWhenOverrideAbsentOnInheritedMethod : Symbol(RejectWhenOverrideAbsentOnInheritedMethod, Decl(noImplicitOverride.ts, 0, 0)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + toString(): string { return 'foo'; }; +>toString : Symbol(RejectWhenOverrideAbsentOnInheritedMethod.toString, Decl(noImplicitOverride.ts, 4, 64)) +} +class AcceptWhenOverridePresentOnInheritedMethod extends Object { +>AcceptWhenOverridePresentOnInheritedMethod : Symbol(AcceptWhenOverridePresentOnInheritedMethod, Decl(noImplicitOverride.ts, 6, 1)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + override toString(): string { return 'foo'; }; +>toString : Symbol(AcceptWhenOverridePresentOnInheritedMethod.toString, Decl(noImplicitOverride.ts, 7, 65)) +} + +// Similar to previous cases where augmentation from Object is implicit +class RejectWhenOverrideAbsentOnAugmentedProperty { +>RejectWhenOverrideAbsentOnAugmentedProperty : Symbol(RejectWhenOverrideAbsentOnAugmentedProperty, Decl(noImplicitOverride.ts, 9, 1)) + + toString(): string { return 'foo'; }; +>toString : Symbol(RejectWhenOverrideAbsentOnAugmentedProperty.toString, Decl(noImplicitOverride.ts, 12, 51)) +} +class AcceptWhenOverridePresentOnAugumentedProperty extends Object { +>AcceptWhenOverridePresentOnAugumentedProperty : Symbol(AcceptWhenOverridePresentOnAugumentedProperty, Decl(noImplicitOverride.ts, 14, 1)) +>Object : Symbol(Object, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + + override toString(): string { return 'foo'; }; +>toString : Symbol(AcceptWhenOverridePresentOnAugumentedProperty.toString, Decl(noImplicitOverride.ts, 15, 68)) +} + +// This should fail via type mismatch of the return value. +// (test is not specific to the override checking code) +class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { +>RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember : Symbol(RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember, Decl(noImplicitOverride.ts, 17, 1)) + + toString(): number { +>toString : Symbol(RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember.toString, Decl(noImplicitOverride.ts, 21, 71)) + + return -1; + } +} + +// ****************************************************** +// Next set of cases deal with inheritance derived from +// an explicitly defined class. +// ****************************************************** + +class Base { +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + // Public property + public userId: number = 1; +>userId : Symbol(Base.userId, Decl(noImplicitOverride.ts, 32, 12)) + + // Accessor + get name(): string { return 'Base'; } +>name : Symbol(Base.name, Decl(noImplicitOverride.ts, 34, 30)) + + // Typical public method + getMeaningOfLife(): number { return 42; } +>getMeaningOfLife : Symbol(Base.getMeaningOfLife, Decl(noImplicitOverride.ts, 36, 41)) + + // Private method + private processInternal(): void { } +>processInternal : Symbol(Base.processInternal, Decl(noImplicitOverride.ts, 38, 45)) +} + +class RejectWhenOverrideAbsentOnInheritedProperty extends Base { +>RejectWhenOverrideAbsentOnInheritedProperty : Symbol(RejectWhenOverrideAbsentOnInheritedProperty, Decl(noImplicitOverride.ts, 41, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + public userId = 2; +>userId : Symbol(RejectWhenOverrideAbsentOnInheritedProperty.userId, Decl(noImplicitOverride.ts, 43, 64)) +} +class AcceptWhenOverridePresentOnInheritedProperty extends Base { +>AcceptWhenOverridePresentOnInheritedProperty : Symbol(AcceptWhenOverridePresentOnInheritedProperty, Decl(noImplicitOverride.ts, 45, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + public override userId = 2; +>userId : Symbol(AcceptWhenOverridePresentOnInheritedProperty.userId, Decl(noImplicitOverride.ts, 46, 65)) +} + +class RejectWhenOverrideAbsentOnInheritedAccessor extends Base { +>RejectWhenOverrideAbsentOnInheritedAccessor : Symbol(RejectWhenOverrideAbsentOnInheritedAccessor, Decl(noImplicitOverride.ts, 48, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + get name(): string { return 'foo'; }; +>name : Symbol(RejectWhenOverrideAbsentOnInheritedAccessor.name, Decl(noImplicitOverride.ts, 50, 64)) +} +class AcceptWhenOverridePresentOnInheritedAccessor extends Base { +>AcceptWhenOverridePresentOnInheritedAccessor : Symbol(AcceptWhenOverridePresentOnInheritedAccessor, Decl(noImplicitOverride.ts, 52, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + override get name(): string { return 'foo'; }; +>name : Symbol(AcceptWhenOverridePresentOnInheritedAccessor.name, Decl(noImplicitOverride.ts, 53, 65)) +} + +class RejectWhenOverrideAbsentOnInheritedMethod extends Base { +>RejectWhenOverrideAbsentOnInheritedMethod : Symbol(RejectWhenOverrideAbsentOnInheritedMethod, Decl(noImplicitOverride.ts, 55, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + getMeaningOfLife(): number { return 24; }; +>getMeaningOfLife : Symbol(RejectWhenOverrideAbsentOnInheritedMethod.getMeaningOfLife, Decl(noImplicitOverride.ts, 57, 62)) +} +class AcceptWhenOverridePresentOnInheritedMethod extends Base { +>AcceptWhenOverridePresentOnInheritedMethod : Symbol(AcceptWhenOverridePresentOnInheritedMethod, Decl(noImplicitOverride.ts, 59, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + override getMeaningOfLife(): number { return 24; }; +>getMeaningOfLife : Symbol(AcceptWhenOverridePresentOnInheritedMethod.getMeaningOfLife, Decl(noImplicitOverride.ts, 60, 63)) +} + +class RejectWhenOverridePresentWithPrivateModifier extends Base { +>RejectWhenOverridePresentWithPrivateModifier : Symbol(RejectWhenOverridePresentWithPrivateModifier, Decl(noImplicitOverride.ts, 62, 1)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 25, 1)) + + private override processInternal() { } +>processInternal : Symbol(RejectWhenOverridePresentWithPrivateModifier.processInternal, Decl(noImplicitOverride.ts, 64, 65)) +} + +// ****************************************************** +// Next set of cases deal with override within interfaces +// and abstract classes (where is should not be present). +// ****************************************************** + +interface Shape { +>Shape : Symbol(Shape, Decl(noImplicitOverride.ts, 66, 1)) + + getWidth(): number; +>getWidth : Symbol(Shape.getWidth, Decl(noImplicitOverride.ts, 73, 17)) +} + +interface RejectWhenOverridePresentOnInterfaceDeclaration extends Shape { +>RejectWhenOverridePresentOnInterfaceDeclaration : Symbol(RejectWhenOverridePresentOnInterfaceDeclaration, Decl(noImplicitOverride.ts, 75, 1)) +>Shape : Symbol(Shape, Decl(noImplicitOverride.ts, 66, 1)) + + override getWidth(): number; +>getWidth : Symbol(RejectWhenOverridePresentOnInterfaceDeclaration.getWidth, Decl(noImplicitOverride.ts, 77, 73)) +} + +interface AcceptWhenOverrideAbsentOnInterfaceDeclaration extends Shape { +>AcceptWhenOverrideAbsentOnInterfaceDeclaration : Symbol(AcceptWhenOverrideAbsentOnInterfaceDeclaration, Decl(noImplicitOverride.ts, 79, 1)) +>Shape : Symbol(Shape, Decl(noImplicitOverride.ts, 66, 1)) + + getWidth(): number; +>getWidth : Symbol(AcceptWhenOverrideAbsentOnInterfaceDeclaration.getWidth, Decl(noImplicitOverride.ts, 81, 72)) +} + +// ****************************************************** +// Next set of cases deal with override with abstract +// classes. +// ****************************************************** + +abstract class Animal { +>Animal : Symbol(Animal, Decl(noImplicitOverride.ts, 83, 1)) + + protected readonly name: string +>name : Symbol(Animal.name, Decl(noImplicitOverride.ts, 90, 23)) + + constructor(name: string) { +>name : Symbol(name, Decl(noImplicitOverride.ts, 93, 16)) + + this.name = name; +>this.name : Symbol(Animal.name, Decl(noImplicitOverride.ts, 90, 23)) +>this : Symbol(Animal, Decl(noImplicitOverride.ts, 83, 1)) +>name : Symbol(Animal.name, Decl(noImplicitOverride.ts, 90, 23)) +>name : Symbol(name, Decl(noImplicitOverride.ts, 93, 16)) + } + + abstract speak(): string; +>speak : Symbol(Animal.speak, Decl(noImplicitOverride.ts, 95, 5)) +} + +abstract class RejectWhenOverridePresentWithAbstractModifier extends Animal { +>RejectWhenOverridePresentWithAbstractModifier : Symbol(RejectWhenOverridePresentWithAbstractModifier, Decl(noImplicitOverride.ts, 98, 1)) +>Animal : Symbol(Animal, Decl(noImplicitOverride.ts, 83, 1)) + + abstract override speak(): string; +>speak : Symbol(RejectWhenOverridePresentWithAbstractModifier.speak, Decl(noImplicitOverride.ts, 100, 77)) +} + +abstract class AcceptWhenOverridePresentOnConcreteDeclaration extends Animal { +>AcceptWhenOverridePresentOnConcreteDeclaration : Symbol(AcceptWhenOverridePresentOnConcreteDeclaration, Decl(noImplicitOverride.ts, 102, 1)) +>Animal : Symbol(Animal, Decl(noImplicitOverride.ts, 83, 1)) + + override speak(): string { return "Woof!"; } +>speak : Symbol(AcceptWhenOverridePresentOnConcreteDeclaration.speak, Decl(noImplicitOverride.ts, 104, 78)) +} + +// ****************************************************** +// Next set of cases deal with override with mixins +// ****************************************************** + +const mixin = {}>(Base: BC) => class extends Base { +>mixin : Symbol(mixin, Decl(noImplicitOverride.ts, 112, 5)) +>BC : Symbol(BC, Decl(noImplicitOverride.ts, 112, 15)) +>args : Symbol(args, Decl(noImplicitOverride.ts, 112, 31)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 112, 54)) +>BC : Symbol(BC, Decl(noImplicitOverride.ts, 112, 15)) +>Base : Symbol(Base, Decl(noImplicitOverride.ts, 112, 54)) + + mixedIn() {} +>mixedIn : Symbol((Anonymous class).mixedIn, Decl(noImplicitOverride.ts, 112, 87)) + +}; + +class A { +>A : Symbol(A, Decl(noImplicitOverride.ts, 114, 2)) + + normal() {} +>normal : Symbol(A.normal, Decl(noImplicitOverride.ts, 116, 9)) +} + +class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(A) { +>RejectWhenOverrideAbsentOnInheritedMethodMixin : Symbol(RejectWhenOverrideAbsentOnInheritedMethodMixin, Decl(noImplicitOverride.ts, 118, 1)) +>mixin : Symbol(mixin, Decl(noImplicitOverride.ts, 112, 5)) +>A : Symbol(A, Decl(noImplicitOverride.ts, 114, 2)) + + normal() {} +>normal : Symbol(RejectWhenOverrideAbsentOnInheritedMethodMixin.normal, Decl(noImplicitOverride.ts, 120, 71)) + + mixedIn() {} +>mixedIn : Symbol(RejectWhenOverrideAbsentOnInheritedMethodMixin.mixedIn, Decl(noImplicitOverride.ts, 121, 15)) +} + +class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(A) { +>AcceptWhenOverridePresentOnInheritedMethodMixin : Symbol(AcceptWhenOverridePresentOnInheritedMethodMixin, Decl(noImplicitOverride.ts, 123, 1)) +>mixin : Symbol(mixin, Decl(noImplicitOverride.ts, 112, 5)) +>A : Symbol(A, Decl(noImplicitOverride.ts, 114, 2)) + + override normal() {} +>normal : Symbol(AcceptWhenOverridePresentOnInheritedMethodMixin.normal, Decl(noImplicitOverride.ts, 125, 72)) + + override mixedIn() {} +>mixedIn : Symbol(AcceptWhenOverridePresentOnInheritedMethodMixin.mixedIn, Decl(noImplicitOverride.ts, 126, 24)) +} + +// ******************************************************** +// Next set of cases deal with override specified via JsDoc +// ******************************************************** + +//class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { +// /** @override */ public speak(): string { return "Woof!" } +//} + diff --git a/tests/baselines/reference/noImplicitOverride.types b/tests/baselines/reference/noImplicitOverride.types new file mode 100644 index 0000000000000..b29fbc0d5a911 --- /dev/null +++ b/tests/baselines/reference/noImplicitOverride.types @@ -0,0 +1,271 @@ +=== tests/cases/compiler/noImplicitOverride.ts === +// ****************************************************** +// First set of cases deal with inheritance from Object. +// ****************************************************** + +class RejectWhenOverrideAbsentOnInheritedMethod extends Object { +>RejectWhenOverrideAbsentOnInheritedMethod : RejectWhenOverrideAbsentOnInheritedMethod +>Object : Object + + toString(): string { return 'foo'; }; +>toString : () => string +>'foo' : "foo" +} +class AcceptWhenOverridePresentOnInheritedMethod extends Object { +>AcceptWhenOverridePresentOnInheritedMethod : AcceptWhenOverridePresentOnInheritedMethod +>Object : Object + + override toString(): string { return 'foo'; }; +>toString : () => string +>'foo' : "foo" +} + +// Similar to previous cases where augmentation from Object is implicit +class RejectWhenOverrideAbsentOnAugmentedProperty { +>RejectWhenOverrideAbsentOnAugmentedProperty : RejectWhenOverrideAbsentOnAugmentedProperty + + toString(): string { return 'foo'; }; +>toString : () => string +>'foo' : "foo" +} +class AcceptWhenOverridePresentOnAugumentedProperty extends Object { +>AcceptWhenOverridePresentOnAugumentedProperty : AcceptWhenOverridePresentOnAugumentedProperty +>Object : Object + + override toString(): string { return 'foo'; }; +>toString : () => string +>'foo' : "foo" +} + +// This should fail via type mismatch of the return value. +// (test is not specific to the override checking code) +class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { +>RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember : RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember + + toString(): number { +>toString : () => number + + return -1; +>-1 : -1 +>1 : 1 + } +} + +// ****************************************************** +// Next set of cases deal with inheritance derived from +// an explicitly defined class. +// ****************************************************** + +class Base { +>Base : Base + + // Public property + public userId: number = 1; +>userId : number +>1 : 1 + + // Accessor + get name(): string { return 'Base'; } +>name : string +>'Base' : "Base" + + // Typical public method + getMeaningOfLife(): number { return 42; } +>getMeaningOfLife : () => number +>42 : 42 + + // Private method + private processInternal(): void { } +>processInternal : () => void +} + +class RejectWhenOverrideAbsentOnInheritedProperty extends Base { +>RejectWhenOverrideAbsentOnInheritedProperty : RejectWhenOverrideAbsentOnInheritedProperty +>Base : Base + + public userId = 2; +>userId : number +>2 : 2 +} +class AcceptWhenOverridePresentOnInheritedProperty extends Base { +>AcceptWhenOverridePresentOnInheritedProperty : AcceptWhenOverridePresentOnInheritedProperty +>Base : Base + + public override userId = 2; +>userId : number +>2 : 2 +} + +class RejectWhenOverrideAbsentOnInheritedAccessor extends Base { +>RejectWhenOverrideAbsentOnInheritedAccessor : RejectWhenOverrideAbsentOnInheritedAccessor +>Base : Base + + get name(): string { return 'foo'; }; +>name : string +>'foo' : "foo" +} +class AcceptWhenOverridePresentOnInheritedAccessor extends Base { +>AcceptWhenOverridePresentOnInheritedAccessor : AcceptWhenOverridePresentOnInheritedAccessor +>Base : Base + + override get name(): string { return 'foo'; }; +>name : string +>'foo' : "foo" +} + +class RejectWhenOverrideAbsentOnInheritedMethod extends Base { +>RejectWhenOverrideAbsentOnInheritedMethod : RejectWhenOverrideAbsentOnInheritedMethod +>Base : Base + + getMeaningOfLife(): number { return 24; }; +>getMeaningOfLife : () => number +>24 : 24 +} +class AcceptWhenOverridePresentOnInheritedMethod extends Base { +>AcceptWhenOverridePresentOnInheritedMethod : AcceptWhenOverridePresentOnInheritedMethod +>Base : Base + + override getMeaningOfLife(): number { return 24; }; +>getMeaningOfLife : () => number +>24 : 24 +} + +class RejectWhenOverridePresentWithPrivateModifier extends Base { +>RejectWhenOverridePresentWithPrivateModifier : RejectWhenOverridePresentWithPrivateModifier +>Base : Base + + private override processInternal() { } +>processInternal : () => void +} + +// ****************************************************** +// Next set of cases deal with override within interfaces +// and abstract classes (where is should not be present). +// ****************************************************** + +interface Shape { +>Shape : Shape + + getWidth(): number; +>getWidth : () => number +} + +interface RejectWhenOverridePresentOnInterfaceDeclaration extends Shape { +>RejectWhenOverridePresentOnInterfaceDeclaration : RejectWhenOverridePresentOnInterfaceDeclaration +>Shape : Shape + + override getWidth(): number; +>getWidth : () => number +} + +interface AcceptWhenOverrideAbsentOnInterfaceDeclaration extends Shape { +>AcceptWhenOverrideAbsentOnInterfaceDeclaration : AcceptWhenOverrideAbsentOnInterfaceDeclaration +>Shape : Shape + + getWidth(): number; +>getWidth : () => number +} + +// ****************************************************** +// Next set of cases deal with override with abstract +// classes. +// ****************************************************** + +abstract class Animal { +>Animal : Animal + + protected readonly name: string +>name : string + + constructor(name: string) { +>name : string + + this.name = name; +>this.name = name : string +>this.name : string +>this : this +>name : string +>name : string + } + + abstract speak(): string; +>speak : () => string +} + +abstract class RejectWhenOverridePresentWithAbstractModifier extends Animal { +>RejectWhenOverridePresentWithAbstractModifier : RejectWhenOverridePresentWithAbstractModifier +>Animal : Animal + + abstract override speak(): string; +>speak : () => string +} + +abstract class AcceptWhenOverridePresentOnConcreteDeclaration extends Animal { +>AcceptWhenOverridePresentOnConcreteDeclaration : AcceptWhenOverridePresentOnConcreteDeclaration +>Animal : Animal + + override speak(): string { return "Woof!"; } +>speak : () => string +>"Woof!" : "Woof!" +} + +// ****************************************************** +// Next set of cases deal with override with mixins +// ****************************************************** + +const mixin = {}>(Base: BC) => class extends Base { +>mixin : {}>(Base: BC) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & BC +> {}>(Base: BC) => class extends Base { mixedIn() {}} : {}>(Base: BC) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & BC +>BC : BC +>args : any[] +>Base : BC +>BC : BC +>class extends Base { mixedIn() {}} : { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & BC +>Base : {} + + mixedIn() {} +>mixedIn : () => void + +}; + +class A { +>A : A + + normal() {} +>normal : () => void +} + +class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(A) { +>RejectWhenOverrideAbsentOnInheritedMethodMixin : RejectWhenOverrideAbsentOnInheritedMethodMixin +>mixin(A) : .(Anonymous class) & A +>mixin : {}>(Base: BC) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & BC +>A : typeof A + + normal() {} +>normal : () => void + + mixedIn() {} +>mixedIn : () => void +} + +class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(A) { +>AcceptWhenOverridePresentOnInheritedMethodMixin : AcceptWhenOverridePresentOnInheritedMethodMixin +>mixin(A) : .(Anonymous class) & A +>mixin : {}>(Base: BC) => { new (...args: any[]): (Anonymous class); prototype: .(Anonymous class); } & BC +>A : typeof A + + override normal() {} +>normal : () => void + + override mixedIn() {} +>mixedIn : () => void +} + +// ******************************************************** +// Next set of cases deal with override specified via JsDoc +// ******************************************************** + +//class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { +// /** @override */ public speak(): string { return "Woof!" } +//} + diff --git a/tests/baselines/reference/overrideKeywordEs5.errors.txt b/tests/baselines/reference/overrideKeywordEs5.errors.txt index 7acba2cd39852..8c249dbd81f64 100644 --- a/tests/baselines/reference/overrideKeywordEs5.errors.txt +++ b/tests/baselines/reference/overrideKeywordEs5.errors.txt @@ -1,32 +1,33 @@ -tests/cases/compiler/overrideKeywordEs5.ts(29,72): error TS1029: 'public' modifier must precede 'override' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(30,75): error TS1029: 'protected' modifier must precede 'override' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(31,70): error TS1029: 'override' modifier must precede 'static' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(33,74): error TS1029: 'override' modifier must precede 'readonly' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(37,21): error TS1030: 'override' modifier already seen. -tests/cases/compiler/overrideKeywordEs5.ts(41,7): error TS2415: Class 'RejectWhenOverridePrivateMethod' incorrectly extends base class 'Base'. +tests/cases/compiler/overrideKeywordEs5.ts(28,72): error TS1029: 'public' modifier must precede 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(29,75): error TS1029: 'protected' modifier must precede 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(30,70): error TS1029: 'override' modifier must precede 'static' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(32,74): error TS1029: 'override' modifier must precede 'readonly' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(36,21): error TS1030: 'override' modifier already seen. +tests/cases/compiler/overrideKeywordEs5.ts(40,7): error TS2415: Class 'RejectWhenOverridePrivateMethod' incorrectly extends base class 'Base'. Types have separate declarations of a private property 'toStringPrivate'. -tests/cases/compiler/overrideKeywordEs5.ts(42,13): error TS1243: 'private' modifier cannot be used with 'override' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(43,14): error TS1243: 'private' modifier cannot be used with 'override' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(48,14): error TS1243: 'abstract' modifier cannot be used with 'override' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(49,14): error TS1243: 'override' modifier cannot be used with 'abstract' modifier. -tests/cases/compiler/overrideKeywordEs5.ts(64,7): error TS2417: Class static side 'typeof RejectWhenOverrideChangesAccessModifier' incorrectly extends base class static side 'typeof Base'. +tests/cases/compiler/overrideKeywordEs5.ts(41,13): error TS1243: 'private' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(42,14): error TS1243: 'private' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(47,14): error TS1243: 'abstract' modifier cannot be used with 'override' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(48,14): error TS1243: 'override' modifier cannot be used with 'abstract' modifier. +tests/cases/compiler/overrideKeywordEs5.ts(63,7): error TS2417: Class static side 'typeof RejectWhenOverrideChangesAccessModifier' incorrectly extends base class static side 'typeof Base'. Property 'toStringStatic' is protected in type 'typeof RejectWhenOverrideChangesAccessModifier' but public in type 'typeof Base'. -tests/cases/compiler/overrideKeywordEs5.ts(76,5): error TS90035: override modifier cannot be used with an optional property declaration -tests/cases/compiler/overrideKeywordEs5.ts(81,18): error TS2699: Accessors must both be override or non-override. -tests/cases/compiler/overrideKeywordEs5.ts(82,18): error TS2699: Accessors must both be override or non-override. -tests/cases/compiler/overrideKeywordEs5.ts(87,21): error TS90032: Class member 'iDontExist' was marked 'override', but no matching declaration was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' -tests/cases/compiler/overrideKeywordEs5.ts(92,7): error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. +tests/cases/compiler/overrideKeywordEs5.ts(75,5): error TS2572: Override modifier cannot be used with an optional property declaration +tests/cases/compiler/overrideKeywordEs5.ts(80,18): error TS2567: Accessors must both be override or non-override. +tests/cases/compiler/overrideKeywordEs5.ts(81,18): error TS2567: Accessors must both be override or non-override. +tests/cases/compiler/overrideKeywordEs5.ts(86,21): error TS2569: Class member 'iDontExist' was marked 'override', but no matching declaration was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' +tests/cases/compiler/overrideKeywordEs5.ts(91,7): error TS2415: Class 'RejectWhenOverrideHasMismatchedType' incorrectly extends base class 'Base'. Types of property 'getMeaningOfLife' are incompatible. Type '() => string' is not assignable to type '() => number'. Type 'string' is not assignable to type 'number'. -tests/cases/compiler/overrideKeywordEs5.ts(98,21): error TS1090: 'override' modifier cannot appear on a parameter. -tests/cases/compiler/overrideKeywordEs5.ts(102,1): error TS1044: 'override' modifier cannot appear on a module or namespace element. -tests/cases/compiler/overrideKeywordEs5.ts(103,1): error TS1044: 'override' modifier cannot appear on a module or namespace element. -tests/cases/compiler/overrideKeywordEs5.ts(107,5): error TS1070: 'override' modifier cannot appear on a type member. +tests/cases/compiler/overrideKeywordEs5.ts(97,21): error TS1090: 'override' modifier cannot appear on a parameter. +tests/cases/compiler/overrideKeywordEs5.ts(105,7): error TS2515: Non-abstract class 'ConcretePropertyClass' does not implement inherited abstract member 'x' from class 'AbstractPropertyBase'. +tests/cases/compiler/overrideKeywordEs5.ts(106,14): error TS1090: 'override' modifier cannot appear on a parameter. +tests/cases/compiler/overrideKeywordEs5.ts(113,1): error TS1044: 'override' modifier cannot appear on a module or namespace element. +tests/cases/compiler/overrideKeywordEs5.ts(114,1): error TS1044: 'override' modifier cannot appear on a module or namespace element. +tests/cases/compiler/overrideKeywordEs5.ts(118,5): error TS1070: 'override' modifier cannot appear on a type member. -==== tests/cases/compiler/overrideKeywordEs5.ts (20 errors) ==== - +==== tests/cases/compiler/overrideKeywordEs5.ts (22 errors) ==== abstract class AbstractBase { readonly id: string; public wasDisposed?: boolean; @@ -127,24 +128,24 @@ tests/cases/compiler/overrideKeywordEs5.ts(107,5): error TS1070: 'override' modi class RejectWhenOverrideOptionalProperty extends Base { public override wasDisposed?: boolean; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS90035: override modifier cannot be used with an optional property declaration +!!! error TS2572: Override modifier cannot be used with an optional property declaration } // If one accessor is marked override, they both should be. class RejectWhenAccessorNotBothOverride extends Base { override get name() { return ''; } ~~~~ -!!! error TS2699: Accessors must both be override or non-override. +!!! error TS2567: Accessors must both be override or non-override. /* */ set name(n: string) {} ~~~~ -!!! error TS2699: Accessors must both be override or non-override. +!!! error TS2567: Accessors must both be override or non-override. } // Compiler should detect when override member is not inherited or augmented class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { public override iDontExist() { return ''; } ~~~~~~~~~~ -!!! error TS90032: Class member 'iDontExist' was marked 'override', but no matching declaration was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' +!!! error TS2569: Class member 'iDontExist' was marked 'override', but no matching declaration was found in any supertype of 'RejectWhenOverrideMarkedOnNonInheritedMember' } // Compiler already detects overriden assignability mismatches, @@ -165,6 +166,22 @@ tests/cases/compiler/overrideKeywordEs5.ts(107,5): error TS1070: 'override' modi !!! error TS1090: 'override' modifier cannot appear on a parameter. } + // But can be be used on parameter properties + + abstract class AbstractPropertyBase { + abstract x: number; + } + class ConcretePropertyClass extends AbstractPropertyBase { + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2515: Non-abstract class 'ConcretePropertyClass' does not implement inherited abstract member 'x' from class 'AbstractPropertyBase'. + constructor(override x: number) { + ~~~~~~~~ +!!! error TS1090: 'override' modifier cannot appear on a parameter. + super(); + } + } + + // Override is not used on class... override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } ~~~~~~~~ @@ -180,7 +197,7 @@ tests/cases/compiler/overrideKeywordEs5.ts(107,5): error TS1070: 'override' modi !!! error TS1070: 'override' modifier cannot appear on a type member. } - /* @mhegazy: is this an appropriate test for consecutive declarations? */ + /* Override method should be grouped as consecutive declarations */ class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { override hasOwnProperty(prop: string): boolean { return super.hasOwnProperty(prop); diff --git a/tests/baselines/reference/overrideKeywordEs5.js b/tests/baselines/reference/overrideKeywordEs5.js index c676203528323..3b28aa71a1938 100644 --- a/tests/baselines/reference/overrideKeywordEs5.js +++ b/tests/baselines/reference/overrideKeywordEs5.js @@ -1,5 +1,4 @@ //// [overrideKeywordEs5.ts] - abstract class AbstractBase { readonly id: string; public wasDisposed?: boolean; @@ -99,6 +98,18 @@ class RejectWhenOverrideIsOnAParameter { public sayHello(override name: string) { return 'hi'; } } +// But can be be used on parameter properties + +abstract class AbstractPropertyBase { + abstract x: number; +} +class ConcretePropertyClass extends AbstractPropertyBase { + constructor(override x: number) { + super(); + } +} + + // Override is not used on class... override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } @@ -108,7 +119,7 @@ interface RejectWhenOverrideInAnInterface { override sayHello(name: string); } -/* @mhegazy: is this an appropriate test for consecutive declarations? */ +/* Override method should be grouped as consecutive declarations */ class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { override hasOwnProperty(prop: string): boolean { return super.hasOwnProperty(prop); @@ -135,7 +146,7 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); -var AbstractBase = (function () { +var AbstractBase = /** @class */ (function () { function AbstractBase() { } Object.defineProperty(AbstractBase.prototype, "name", { @@ -153,7 +164,7 @@ var AbstractBase = (function () { AbstractBase.prototype.getMeaningOfLife = function () { return 42; }; return AbstractBase; }()); -var Base = (function (_super) { +var Base = /** @class */ (function (_super) { __extends(Base, _super); function Base() { return _super !== null && _super.apply(this, arguments) || this; @@ -166,7 +177,7 @@ var Base = (function (_super) { // // [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier // -var RejectWhenOverridePrecedesPublicModifier = (function (_super) { +var RejectWhenOverridePrecedesPublicModifier = /** @class */ (function (_super) { __extends(RejectWhenOverridePrecedesPublicModifier, _super); function RejectWhenOverridePrecedesPublicModifier() { return _super !== null && _super.apply(this, arguments) || this; @@ -175,7 +186,7 @@ var RejectWhenOverridePrecedesPublicModifier = (function (_super) { ; return RejectWhenOverridePrecedesPublicModifier; }(Base)); -var RejectWhenOverridePrecedesProtectedModifier = (function (_super) { +var RejectWhenOverridePrecedesProtectedModifier = /** @class */ (function (_super) { __extends(RejectWhenOverridePrecedesProtectedModifier, _super); function RejectWhenOverridePrecedesProtectedModifier() { return _super !== null && _super.apply(this, arguments) || this; @@ -184,7 +195,7 @@ var RejectWhenOverridePrecedesProtectedModifier = (function (_super) { ; return RejectWhenOverridePrecedesProtectedModifier; }(Base)); -var RejectWhenStaticPrecedesOverrideModifier = (function (_super) { +var RejectWhenStaticPrecedesOverrideModifier = /** @class */ (function (_super) { __extends(RejectWhenStaticPrecedesOverrideModifier, _super); function RejectWhenStaticPrecedesOverrideModifier() { return _super !== null && _super.apply(this, arguments) || this; @@ -193,7 +204,7 @@ var RejectWhenStaticPrecedesOverrideModifier = (function (_super) { ; return RejectWhenStaticPrecedesOverrideModifier; }(Base)); -var AcceptWhenOverrideFollowsAccessModifier = (function (_super) { +var AcceptWhenOverrideFollowsAccessModifier = /** @class */ (function (_super) { __extends(AcceptWhenOverrideFollowsAccessModifier, _super); function AcceptWhenOverrideFollowsAccessModifier() { return _super !== null && _super.apply(this, arguments) || this; @@ -201,7 +212,7 @@ var AcceptWhenOverrideFollowsAccessModifier = (function (_super) { AcceptWhenOverrideFollowsAccessModifier.prototype.toStringPublic = function () { return ''; }; return AcceptWhenOverrideFollowsAccessModifier; }(Base)); -var RejectWhenReadonlyPrecedesOverrideModifier = (function (_super) { +var RejectWhenReadonlyPrecedesOverrideModifier = /** @class */ (function (_super) { __extends(RejectWhenReadonlyPrecedesOverrideModifier, _super); function RejectWhenReadonlyPrecedesOverrideModifier() { return _super !== null && _super.apply(this, arguments) || this; @@ -209,7 +220,7 @@ var RejectWhenReadonlyPrecedesOverrideModifier = (function (_super) { return RejectWhenReadonlyPrecedesOverrideModifier; }(Base)); // Modifiers should never be repeated -var RejectWhenOverrideIsRepeated = (function (_super) { +var RejectWhenOverrideIsRepeated = /** @class */ (function (_super) { __extends(RejectWhenOverrideIsRepeated, _super); function RejectWhenOverrideIsRepeated() { return _super !== null && _super.apply(this, arguments) || this; @@ -218,7 +229,7 @@ var RejectWhenOverrideIsRepeated = (function (_super) { return RejectWhenOverrideIsRepeated; }(Base)); // You cannot override a private method -var RejectWhenOverridePrivateMethod = (function (_super) { +var RejectWhenOverridePrivateMethod = /** @class */ (function (_super) { __extends(RejectWhenOverridePrivateMethod, _super); function RejectWhenOverridePrivateMethod() { return _super !== null && _super.apply(this, arguments) || this; @@ -228,7 +239,7 @@ var RejectWhenOverridePrivateMethod = (function (_super) { return RejectWhenOverridePrivateMethod; }(Base)); // Override and abstract on methods are orthogonal, should never be used together -var RejectWhenOverrideAbstractMethod = (function (_super) { +var RejectWhenOverrideAbstractMethod = /** @class */ (function (_super) { __extends(RejectWhenOverrideAbstractMethod, _super); function RejectWhenOverrideAbstractMethod() { return _super !== null && _super.apply(this, arguments) || this; @@ -236,7 +247,7 @@ var RejectWhenOverrideAbstractMethod = (function (_super) { return RejectWhenOverrideAbstractMethod; }(AbstractBase)); // Acceptable to provide an override implementation in an abstract class however -var AcceptWhenOverrideInAbstractClass = (function (_super) { +var AcceptWhenOverrideInAbstractClass = /** @class */ (function (_super) { __extends(AcceptWhenOverrideInAbstractClass, _super); function AcceptWhenOverrideInAbstractClass() { return _super !== null && _super.apply(this, arguments) || this; @@ -245,7 +256,7 @@ var AcceptWhenOverrideInAbstractClass = (function (_super) { return AcceptWhenOverrideInAbstractClass; }(AbstractBase)); // Override checks are allowed on static methods -var AcceptWhenOverrideStaticMethod = (function (_super) { +var AcceptWhenOverrideStaticMethod = /** @class */ (function (_super) { __extends(AcceptWhenOverrideStaticMethod, _super); function AcceptWhenOverrideStaticMethod() { return _super !== null && _super.apply(this, arguments) || this; @@ -255,7 +266,7 @@ var AcceptWhenOverrideStaticMethod = (function (_super) { }(Base)); // Compiler already checks for access modifier narrowing, // override does not alter these semantics. -var RejectWhenOverrideChangesAccessModifier = (function (_super) { +var RejectWhenOverrideChangesAccessModifier = /** @class */ (function (_super) { __extends(RejectWhenOverrideChangesAccessModifier, _super); function RejectWhenOverrideChangesAccessModifier() { return _super !== null && _super.apply(this, arguments) || this; @@ -265,7 +276,7 @@ var RejectWhenOverrideChangesAccessModifier = (function (_super) { }(Base)); // Compiler should be able to traverse multiple levels of inheritance // to assess for overriden members (already does this). -var AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass = (function (_super) { +var AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass = /** @class */ (function (_super) { __extends(AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass, _super); function AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass() { return _super !== null && _super.apply(this, arguments) || this; @@ -274,7 +285,7 @@ var AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass = (function (_super) return AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass; }(Base)); // Override cannot be used with optional property. -var RejectWhenOverrideOptionalProperty = (function (_super) { +var RejectWhenOverrideOptionalProperty = /** @class */ (function (_super) { __extends(RejectWhenOverrideOptionalProperty, _super); function RejectWhenOverrideOptionalProperty() { return _super !== null && _super.apply(this, arguments) || this; @@ -282,7 +293,7 @@ var RejectWhenOverrideOptionalProperty = (function (_super) { return RejectWhenOverrideOptionalProperty; }(Base)); // If one accessor is marked override, they both should be. -var RejectWhenAccessorNotBothOverride = (function (_super) { +var RejectWhenAccessorNotBothOverride = /** @class */ (function (_super) { __extends(RejectWhenAccessorNotBothOverride, _super); function RejectWhenAccessorNotBothOverride() { return _super !== null && _super.apply(this, arguments) || this; @@ -296,7 +307,7 @@ var RejectWhenAccessorNotBothOverride = (function (_super) { return RejectWhenAccessorNotBothOverride; }(Base)); // Compiler should detect when override member is not inherited or augmented -var RejectWhenOverrideMarkedOnNonInheritedMember = (function (_super) { +var RejectWhenOverrideMarkedOnNonInheritedMember = /** @class */ (function (_super) { __extends(RejectWhenOverrideMarkedOnNonInheritedMember, _super); function RejectWhenOverrideMarkedOnNonInheritedMember() { return _super !== null && _super.apply(this, arguments) || this; @@ -306,7 +317,7 @@ var RejectWhenOverrideMarkedOnNonInheritedMember = (function (_super) { }(Base)); // Compiler already detects overriden assignability mismatches, // override keyword does not change these semantics -var RejectWhenOverrideHasMismatchedType = (function (_super) { +var RejectWhenOverrideHasMismatchedType = /** @class */ (function (_super) { __extends(RejectWhenOverrideHasMismatchedType, _super); function RejectWhenOverrideHasMismatchedType() { return _super !== null && _super.apply(this, arguments) || this; @@ -315,21 +326,34 @@ var RejectWhenOverrideHasMismatchedType = (function (_super) { return RejectWhenOverrideHasMismatchedType; }(Base)); // Override is not be used on parameters -var RejectWhenOverrideIsOnAParameter = (function () { +var RejectWhenOverrideIsOnAParameter = /** @class */ (function () { function RejectWhenOverrideIsOnAParameter() { } RejectWhenOverrideIsOnAParameter.prototype.sayHello = function (name) { return 'hi'; }; return RejectWhenOverrideIsOnAParameter; }()); +// But can be be used on parameter properties +var AbstractPropertyBase = /** @class */ (function () { + function AbstractPropertyBase() { + } + return AbstractPropertyBase; +}()); +var ConcretePropertyClass = /** @class */ (function (_super) { + __extends(ConcretePropertyClass, _super); + function ConcretePropertyClass(x) { + return _super.call(this) || this; + } + return ConcretePropertyClass; +}(AbstractPropertyBase)); // Override is not used on class... -var RejectWhenOverrideIsOnClassDeclaration = (function () { +var RejectWhenOverrideIsOnClassDeclaration = /** @class */ (function () { function RejectWhenOverrideIsOnClassDeclaration() { } RejectWhenOverrideIsOnClassDeclaration.prototype.sayHello = function (name) { return ''; }; return RejectWhenOverrideIsOnClassDeclaration; }()); -/* @mhegazy: is this an appropriate test for consecutive declarations? */ -var RejectWhenOverrideDeclarationsAreNotConsecutive = (function (_super) { +/* Override method should be grouped as consecutive declarations */ +var RejectWhenOverrideDeclarationsAreNotConsecutive = /** @class */ (function (_super) { __extends(RejectWhenOverrideDeclarationsAreNotConsecutive, _super); function RejectWhenOverrideDeclarationsAreNotConsecutive() { return _super !== null && _super.apply(this, arguments) || this; @@ -419,6 +443,12 @@ declare class RejectWhenOverrideHasMismatchedType extends Base { declare class RejectWhenOverrideIsOnAParameter { sayHello(name: string): string; } +declare abstract class AbstractPropertyBase { + abstract x: number; +} +declare class ConcretePropertyClass extends AbstractPropertyBase { + constructor(x: number); +} declare class RejectWhenOverrideIsOnClassDeclaration { sayHello(name: string): string; } diff --git a/tests/baselines/reference/overrideKeywordEs5.symbols b/tests/baselines/reference/overrideKeywordEs5.symbols new file mode 100644 index 0000000000000..737a1e62627e5 --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs5.symbols @@ -0,0 +1,288 @@ +=== tests/cases/compiler/overrideKeywordEs5.ts === +abstract class AbstractBase { +>AbstractBase : Symbol(AbstractBase, Decl(overrideKeywordEs5.ts, 0, 0)) + + readonly id: string; +>id : Symbol(AbstractBase.id, Decl(overrideKeywordEs5.ts, 0, 29)) + + public wasDisposed?: boolean; +>wasDisposed : Symbol(AbstractBase.wasDisposed, Decl(overrideKeywordEs5.ts, 1, 24)) + + private name_: string; +>name_ : Symbol(AbstractBase.name_, Decl(overrideKeywordEs5.ts, 2, 33)) + + get name() { return this.name_; } +>name : Symbol(AbstractBase.name, Decl(overrideKeywordEs5.ts, 3, 26), Decl(overrideKeywordEs5.ts, 4, 37)) +>this.name_ : Symbol(AbstractBase.name_, Decl(overrideKeywordEs5.ts, 2, 33)) +>this : Symbol(AbstractBase, Decl(overrideKeywordEs5.ts, 0, 0)) +>name_ : Symbol(AbstractBase.name_, Decl(overrideKeywordEs5.ts, 2, 33)) + + set name(name: string) { this.name_ = name; } +>name : Symbol(AbstractBase.name, Decl(overrideKeywordEs5.ts, 3, 26), Decl(overrideKeywordEs5.ts, 4, 37)) +>name : Symbol(name, Decl(overrideKeywordEs5.ts, 5, 13)) +>this.name_ : Symbol(AbstractBase.name_, Decl(overrideKeywordEs5.ts, 2, 33)) +>this : Symbol(AbstractBase, Decl(overrideKeywordEs5.ts, 0, 0)) +>name_ : Symbol(AbstractBase.name_, Decl(overrideKeywordEs5.ts, 2, 33)) +>name : Symbol(name, Decl(overrideKeywordEs5.ts, 5, 13)) + + static toStringStatic(): string { return 'static'; } +>toStringStatic : Symbol(AbstractBase.toStringStatic, Decl(overrideKeywordEs5.ts, 5, 49)) + + public toStringPublic(): string { return 'public'; }; +>toStringPublic : Symbol(AbstractBase.toStringPublic, Decl(overrideKeywordEs5.ts, 7, 56)) + + protected toStringProtected(): string { return 'protected'; } +>toStringProtected : Symbol(AbstractBase.toStringProtected, Decl(overrideKeywordEs5.ts, 8, 57)) + + private toStringPrivate(): string { return 'private'; } +>toStringPrivate : Symbol(AbstractBase.toStringPrivate, Decl(overrideKeywordEs5.ts, 9, 65)) + + private toStringPrivate2(): string { return 'private2'; } +>toStringPrivate2 : Symbol(AbstractBase.toStringPrivate2, Decl(overrideKeywordEs5.ts, 10, 59)) + + abstract toStringAbstract(): string; +>toStringAbstract : Symbol(AbstractBase.toStringAbstract, Decl(overrideKeywordEs5.ts, 11, 61)) + + abstract toStringAbstract2(): string; +>toStringAbstract2 : Symbol(AbstractBase.toStringAbstract2, Decl(overrideKeywordEs5.ts, 12, 40)) + + getMeaningOfLife(): number { return 42; } +>getMeaningOfLife : Symbol(AbstractBase.getMeaningOfLife, Decl(overrideKeywordEs5.ts, 13, 41)) +} + +class Base extends AbstractBase { +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>AbstractBase : Symbol(AbstractBase, Decl(overrideKeywordEs5.ts, 0, 0)) + + override toStringAbstract(): string { return 'implemented'; } +>toStringAbstract : Symbol(Base.toStringAbstract, Decl(overrideKeywordEs5.ts, 18, 33)) + + override toStringAbstract2(): string { return 'implemented2'; } +>toStringAbstract2 : Symbol(Base.toStringAbstract2, Decl(overrideKeywordEs5.ts, 19, 65)) +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenOverridePrecedesPublicModifier extends Base { override public toStringPublic() { return ''; }; } +>RejectWhenOverridePrecedesPublicModifier : Symbol(RejectWhenOverridePrecedesPublicModifier, Decl(overrideKeywordEs5.ts, 21, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>toStringPublic : Symbol(RejectWhenOverridePrecedesPublicModifier.toStringPublic, Decl(overrideKeywordEs5.ts, 27, 61)) + +class RejectWhenOverridePrecedesProtectedModifier extends Base { override protected toStringProtected() { return ''; }; } +>RejectWhenOverridePrecedesProtectedModifier : Symbol(RejectWhenOverridePrecedesProtectedModifier, Decl(overrideKeywordEs5.ts, 27, 112)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>toStringProtected : Symbol(RejectWhenOverridePrecedesProtectedModifier.toStringProtected, Decl(overrideKeywordEs5.ts, 28, 64)) + +class RejectWhenStaticPrecedesOverrideModifier extends Base { static override toStringStatic() { return ''; }; } +>RejectWhenStaticPrecedesOverrideModifier : Symbol(RejectWhenStaticPrecedesOverrideModifier, Decl(overrideKeywordEs5.ts, 28, 121)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>toStringStatic : Symbol(RejectWhenStaticPrecedesOverrideModifier.toStringStatic, Decl(overrideKeywordEs5.ts, 29, 61)) + +class AcceptWhenOverrideFollowsAccessModifier extends Base { public override toStringPublic() { return ''; } } +>AcceptWhenOverrideFollowsAccessModifier : Symbol(AcceptWhenOverrideFollowsAccessModifier, Decl(overrideKeywordEs5.ts, 29, 112)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>toStringPublic : Symbol(AcceptWhenOverrideFollowsAccessModifier.toStringPublic, Decl(overrideKeywordEs5.ts, 30, 60)) + +class RejectWhenReadonlyPrecedesOverrideModifier extends Base { readonly override id: string; } +>RejectWhenReadonlyPrecedesOverrideModifier : Symbol(RejectWhenReadonlyPrecedesOverrideModifier, Decl(overrideKeywordEs5.ts, 30, 110)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>id : Symbol(RejectWhenReadonlyPrecedesOverrideModifier.id, Decl(overrideKeywordEs5.ts, 31, 63)) + +// Modifiers should never be repeated +class RejectWhenOverrideIsRepeated extends Base { +>RejectWhenOverrideIsRepeated : Symbol(RejectWhenOverrideIsRepeated, Decl(overrideKeywordEs5.ts, 31, 95)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + public override override toStringPublic() { return ''; } +>toStringPublic : Symbol(RejectWhenOverrideIsRepeated.toStringPublic, Decl(overrideKeywordEs5.ts, 34, 49)) +} + +// You cannot override a private method +class RejectWhenOverridePrivateMethod extends Base { +>RejectWhenOverridePrivateMethod : Symbol(RejectWhenOverridePrivateMethod, Decl(overrideKeywordEs5.ts, 36, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + private override toStringPrivate() { return ''; } +>toStringPrivate : Symbol(RejectWhenOverridePrivateMethod.toStringPrivate, Decl(overrideKeywordEs5.ts, 39, 52)) + + override private toStringPrivate2() { return ''; } +>toStringPrivate2 : Symbol(RejectWhenOverridePrivateMethod.toStringPrivate2, Decl(overrideKeywordEs5.ts, 40, 53)) +} + +// Override and abstract on methods are orthogonal, should never be used together +abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { +>RejectWhenOverrideAbstractMethod : Symbol(RejectWhenOverrideAbstractMethod, Decl(overrideKeywordEs5.ts, 42, 1)) +>AbstractBase : Symbol(AbstractBase, Decl(overrideKeywordEs5.ts, 0, 0)) + + abstract override toStringAbstract(): string; +>toStringAbstract : Symbol(RejectWhenOverrideAbstractMethod.toStringAbstract, Decl(overrideKeywordEs5.ts, 45, 70)) + + override abstract toStringAbstract2(): string; +>toStringAbstract2 : Symbol(RejectWhenOverrideAbstractMethod.toStringAbstract2, Decl(overrideKeywordEs5.ts, 46, 49)) +} + +// Acceptable to provide an override implementation in an abstract class however +abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { +>AcceptWhenOverrideInAbstractClass : Symbol(AcceptWhenOverrideInAbstractClass, Decl(overrideKeywordEs5.ts, 48, 1)) +>AbstractBase : Symbol(AbstractBase, Decl(overrideKeywordEs5.ts, 0, 0)) + + override toStringAbstract(): string { return 'implemented in abstract class'; } +>toStringAbstract : Symbol(AcceptWhenOverrideInAbstractClass.toStringAbstract, Decl(overrideKeywordEs5.ts, 51, 71)) +} + +// Override checks are allowed on static methods +class AcceptWhenOverrideStaticMethod extends Base { +>AcceptWhenOverrideStaticMethod : Symbol(AcceptWhenOverrideStaticMethod, Decl(overrideKeywordEs5.ts, 53, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + override static toStringStatic() { return 'static'; } +>toStringStatic : Symbol(AcceptWhenOverrideStaticMethod.toStringStatic, Decl(overrideKeywordEs5.ts, 56, 51)) +} + +// Compiler already checks for access modifier narrowing, +// override does not alter these semantics. +class RejectWhenOverrideChangesAccessModifier extends Base { +>RejectWhenOverrideChangesAccessModifier : Symbol(RejectWhenOverrideChangesAccessModifier, Decl(overrideKeywordEs5.ts, 58, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + protected override static toStringStatic() { return 'member is now protected'; } +>toStringStatic : Symbol(RejectWhenOverrideChangesAccessModifier.toStringStatic, Decl(overrideKeywordEs5.ts, 62, 60)) +} + +// Compiler should be able to traverse multiple levels of inheritance +// to assess for overriden members (already does this). +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { +>AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass : Symbol(AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass, Decl(overrideKeywordEs5.ts, 64, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + override getMeaningOfLife(): number { return 12; } +>getMeaningOfLife : Symbol(AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass.getMeaningOfLife, Decl(overrideKeywordEs5.ts, 68, 75)) +} + +// Override cannot be used with optional property. +class RejectWhenOverrideOptionalProperty extends Base { +>RejectWhenOverrideOptionalProperty : Symbol(RejectWhenOverrideOptionalProperty, Decl(overrideKeywordEs5.ts, 70, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + public override wasDisposed?: boolean; +>wasDisposed : Symbol(RejectWhenOverrideOptionalProperty.wasDisposed, Decl(overrideKeywordEs5.ts, 73, 55)) +} + +// If one accessor is marked override, they both should be. +class RejectWhenAccessorNotBothOverride extends Base { +>RejectWhenAccessorNotBothOverride : Symbol(RejectWhenAccessorNotBothOverride, Decl(overrideKeywordEs5.ts, 75, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + override get name() { return ''; } +>name : Symbol(RejectWhenAccessorNotBothOverride.name, Decl(overrideKeywordEs5.ts, 78, 54), Decl(overrideKeywordEs5.ts, 79, 38)) + + /* */ set name(n: string) {} +>name : Symbol(RejectWhenAccessorNotBothOverride.name, Decl(overrideKeywordEs5.ts, 78, 54), Decl(overrideKeywordEs5.ts, 79, 38)) +>n : Symbol(n, Decl(overrideKeywordEs5.ts, 80, 22)) +} + +// Compiler should detect when override member is not inherited or augmented +class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { +>RejectWhenOverrideMarkedOnNonInheritedMember : Symbol(RejectWhenOverrideMarkedOnNonInheritedMember, Decl(overrideKeywordEs5.ts, 81, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + public override iDontExist() { return ''; } +>iDontExist : Symbol(RejectWhenOverrideMarkedOnNonInheritedMember.iDontExist, Decl(overrideKeywordEs5.ts, 84, 65)) +} + +// Compiler already detects overriden assignability mismatches, +// override keyword does not change these semantics +class RejectWhenOverrideHasMismatchedType extends Base { +>RejectWhenOverrideHasMismatchedType : Symbol(RejectWhenOverrideHasMismatchedType, Decl(overrideKeywordEs5.ts, 86, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + override getMeaningOfLife(): string { return 'the meaning of life is a number, not a string'; } +>getMeaningOfLife : Symbol(RejectWhenOverrideHasMismatchedType.getMeaningOfLife, Decl(overrideKeywordEs5.ts, 90, 56)) +} + +// Override is not be used on parameters +class RejectWhenOverrideIsOnAParameter { +>RejectWhenOverrideIsOnAParameter : Symbol(RejectWhenOverrideIsOnAParameter, Decl(overrideKeywordEs5.ts, 92, 1)) + + public sayHello(override name: string) { return 'hi'; } +>sayHello : Symbol(RejectWhenOverrideIsOnAParameter.sayHello, Decl(overrideKeywordEs5.ts, 95, 40)) +>name : Symbol(name, Decl(overrideKeywordEs5.ts, 96, 20)) +} + +// But can be be used on parameter properties + +abstract class AbstractPropertyBase { +>AbstractPropertyBase : Symbol(AbstractPropertyBase, Decl(overrideKeywordEs5.ts, 97, 1)) + + abstract x: number; +>x : Symbol(AbstractPropertyBase.x, Decl(overrideKeywordEs5.ts, 101, 37)) +} +class ConcretePropertyClass extends AbstractPropertyBase { +>ConcretePropertyClass : Symbol(ConcretePropertyClass, Decl(overrideKeywordEs5.ts, 103, 1)) +>AbstractPropertyBase : Symbol(AbstractPropertyBase, Decl(overrideKeywordEs5.ts, 97, 1)) + + constructor(override x: number) { +>x : Symbol(x, Decl(overrideKeywordEs5.ts, 105, 13)) + + super(); +>super : Symbol(AbstractPropertyBase, Decl(overrideKeywordEs5.ts, 97, 1)) + } +} + + +// Override is not used on class... +override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } +>RejectWhenOverrideIsOnClassDeclaration : Symbol(RejectWhenOverrideIsOnClassDeclaration, Decl(overrideKeywordEs5.ts, 108, 1)) +>sayHello : Symbol(RejectWhenOverrideIsOnClassDeclaration.sayHello, Decl(overrideKeywordEs5.ts, 112, 55)) +>name : Symbol(name, Decl(overrideKeywordEs5.ts, 112, 72)) + +override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } +>RejectWhenOverrideIsOnInterfaceDeclaration : Symbol(RejectWhenOverrideIsOnInterfaceDeclaration, Decl(overrideKeywordEs5.ts, 112, 102)) +>sayHello : Symbol(RejectWhenOverrideIsOnInterfaceDeclaration.sayHello, Decl(overrideKeywordEs5.ts, 113, 63)) +>name : Symbol(name, Decl(overrideKeywordEs5.ts, 113, 73)) + +//... or interface declarations +interface RejectWhenOverrideInAnInterface { +>RejectWhenOverrideInAnInterface : Symbol(RejectWhenOverrideInAnInterface, Decl(overrideKeywordEs5.ts, 113, 89)) + + override sayHello(name: string); +>sayHello : Symbol(RejectWhenOverrideInAnInterface.sayHello, Decl(overrideKeywordEs5.ts, 116, 43)) +>name : Symbol(name, Decl(overrideKeywordEs5.ts, 117, 22)) +} + +/* Override method should be grouped as consecutive declarations */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { +>RejectWhenOverrideDeclarationsAreNotConsecutive : Symbol(RejectWhenOverrideDeclarationsAreNotConsecutive, Decl(overrideKeywordEs5.ts, 118, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) + + override hasOwnProperty(prop: string): boolean { +>hasOwnProperty : Symbol(RejectWhenOverrideDeclarationsAreNotConsecutive.hasOwnProperty, Decl(overrideKeywordEs5.ts, 121, 68)) +>prop : Symbol(prop, Decl(overrideKeywordEs5.ts, 122, 28)) + + return super.hasOwnProperty(prop); +>super.hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.d.ts, --, --)) +>super : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.d.ts, --, --)) +>prop : Symbol(prop, Decl(overrideKeywordEs5.ts, 122, 28)) + } + + public getMeaningOfLife(): number { +>getMeaningOfLife : Symbol(RejectWhenOverrideDeclarationsAreNotConsecutive.getMeaningOfLife, Decl(overrideKeywordEs5.ts, 124, 5)) + + return 42; + } + + override propertyIsEnumerable(prop: string): boolean { +>propertyIsEnumerable : Symbol(RejectWhenOverrideDeclarationsAreNotConsecutive.propertyIsEnumerable, Decl(overrideKeywordEs5.ts, 128, 5)) +>prop : Symbol(prop, Decl(overrideKeywordEs5.ts, 130, 34)) + + return super.propertyIsEnumerable(prop); +>super.propertyIsEnumerable : Symbol(Object.propertyIsEnumerable, Decl(lib.d.ts, --, --)) +>super : Symbol(Base, Decl(overrideKeywordEs5.ts, 16, 1)) +>propertyIsEnumerable : Symbol(Object.propertyIsEnumerable, Decl(lib.d.ts, --, --)) +>prop : Symbol(prop, Decl(overrideKeywordEs5.ts, 130, 34)) + } +} + diff --git a/tests/baselines/reference/overrideKeywordEs5.types b/tests/baselines/reference/overrideKeywordEs5.types new file mode 100644 index 0000000000000..8751ae22e24c6 --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs5.types @@ -0,0 +1,317 @@ +=== tests/cases/compiler/overrideKeywordEs5.ts === +abstract class AbstractBase { +>AbstractBase : AbstractBase + + readonly id: string; +>id : string + + public wasDisposed?: boolean; +>wasDisposed : boolean + + private name_: string; +>name_ : string + + get name() { return this.name_; } +>name : string +>this.name_ : string +>this : this +>name_ : string + + set name(name: string) { this.name_ = name; } +>name : string +>name : string +>this.name_ = name : string +>this.name_ : string +>this : this +>name_ : string +>name : string + + static toStringStatic(): string { return 'static'; } +>toStringStatic : () => string +>'static' : "static" + + public toStringPublic(): string { return 'public'; }; +>toStringPublic : () => string +>'public' : "public" + + protected toStringProtected(): string { return 'protected'; } +>toStringProtected : () => string +>'protected' : "protected" + + private toStringPrivate(): string { return 'private'; } +>toStringPrivate : () => string +>'private' : "private" + + private toStringPrivate2(): string { return 'private2'; } +>toStringPrivate2 : () => string +>'private2' : "private2" + + abstract toStringAbstract(): string; +>toStringAbstract : () => string + + abstract toStringAbstract2(): string; +>toStringAbstract2 : () => string + + getMeaningOfLife(): number { return 42; } +>getMeaningOfLife : () => number +>42 : 42 +} + +class Base extends AbstractBase { +>Base : Base +>AbstractBase : AbstractBase + + override toStringAbstract(): string { return 'implemented'; } +>toStringAbstract : () => string +>'implemented' : "implemented" + + override toStringAbstract2(): string { return 'implemented2'; } +>toStringAbstract2 : () => string +>'implemented2' : "implemented2" +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenOverridePrecedesPublicModifier extends Base { override public toStringPublic() { return ''; }; } +>RejectWhenOverridePrecedesPublicModifier : RejectWhenOverridePrecedesPublicModifier +>Base : Base +>toStringPublic : () => string +>'' : "" + +class RejectWhenOverridePrecedesProtectedModifier extends Base { override protected toStringProtected() { return ''; }; } +>RejectWhenOverridePrecedesProtectedModifier : RejectWhenOverridePrecedesProtectedModifier +>Base : Base +>toStringProtected : () => string +>'' : "" + +class RejectWhenStaticPrecedesOverrideModifier extends Base { static override toStringStatic() { return ''; }; } +>RejectWhenStaticPrecedesOverrideModifier : RejectWhenStaticPrecedesOverrideModifier +>Base : Base +>toStringStatic : () => string +>'' : "" + +class AcceptWhenOverrideFollowsAccessModifier extends Base { public override toStringPublic() { return ''; } } +>AcceptWhenOverrideFollowsAccessModifier : AcceptWhenOverrideFollowsAccessModifier +>Base : Base +>toStringPublic : () => string +>'' : "" + +class RejectWhenReadonlyPrecedesOverrideModifier extends Base { readonly override id: string; } +>RejectWhenReadonlyPrecedesOverrideModifier : RejectWhenReadonlyPrecedesOverrideModifier +>Base : Base +>id : string + +// Modifiers should never be repeated +class RejectWhenOverrideIsRepeated extends Base { +>RejectWhenOverrideIsRepeated : RejectWhenOverrideIsRepeated +>Base : Base + + public override override toStringPublic() { return ''; } +>toStringPublic : () => string +>'' : "" +} + +// You cannot override a private method +class RejectWhenOverridePrivateMethod extends Base { +>RejectWhenOverridePrivateMethod : RejectWhenOverridePrivateMethod +>Base : Base + + private override toStringPrivate() { return ''; } +>toStringPrivate : () => string +>'' : "" + + override private toStringPrivate2() { return ''; } +>toStringPrivate2 : () => string +>'' : "" +} + +// Override and abstract on methods are orthogonal, should never be used together +abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { +>RejectWhenOverrideAbstractMethod : RejectWhenOverrideAbstractMethod +>AbstractBase : AbstractBase + + abstract override toStringAbstract(): string; +>toStringAbstract : () => string + + override abstract toStringAbstract2(): string; +>toStringAbstract2 : () => string +} + +// Acceptable to provide an override implementation in an abstract class however +abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { +>AcceptWhenOverrideInAbstractClass : AcceptWhenOverrideInAbstractClass +>AbstractBase : AbstractBase + + override toStringAbstract(): string { return 'implemented in abstract class'; } +>toStringAbstract : () => string +>'implemented in abstract class' : "implemented in abstract class" +} + +// Override checks are allowed on static methods +class AcceptWhenOverrideStaticMethod extends Base { +>AcceptWhenOverrideStaticMethod : AcceptWhenOverrideStaticMethod +>Base : Base + + override static toStringStatic() { return 'static'; } +>toStringStatic : () => string +>'static' : "static" +} + +// Compiler already checks for access modifier narrowing, +// override does not alter these semantics. +class RejectWhenOverrideChangesAccessModifier extends Base { +>RejectWhenOverrideChangesAccessModifier : RejectWhenOverrideChangesAccessModifier +>Base : Base + + protected override static toStringStatic() { return 'member is now protected'; } +>toStringStatic : () => string +>'member is now protected' : "member is now protected" +} + +// Compiler should be able to traverse multiple levels of inheritance +// to assess for overriden members (already does this). +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { +>AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass : AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass +>Base : Base + + override getMeaningOfLife(): number { return 12; } +>getMeaningOfLife : () => number +>12 : 12 +} + +// Override cannot be used with optional property. +class RejectWhenOverrideOptionalProperty extends Base { +>RejectWhenOverrideOptionalProperty : RejectWhenOverrideOptionalProperty +>Base : Base + + public override wasDisposed?: boolean; +>wasDisposed : boolean +} + +// If one accessor is marked override, they both should be. +class RejectWhenAccessorNotBothOverride extends Base { +>RejectWhenAccessorNotBothOverride : RejectWhenAccessorNotBothOverride +>Base : Base + + override get name() { return ''; } +>name : string +>'' : "" + + /* */ set name(n: string) {} +>name : string +>n : string +} + +// Compiler should detect when override member is not inherited or augmented +class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { +>RejectWhenOverrideMarkedOnNonInheritedMember : RejectWhenOverrideMarkedOnNonInheritedMember +>Base : Base + + public override iDontExist() { return ''; } +>iDontExist : () => string +>'' : "" +} + +// Compiler already detects overriden assignability mismatches, +// override keyword does not change these semantics +class RejectWhenOverrideHasMismatchedType extends Base { +>RejectWhenOverrideHasMismatchedType : RejectWhenOverrideHasMismatchedType +>Base : Base + + override getMeaningOfLife(): string { return 'the meaning of life is a number, not a string'; } +>getMeaningOfLife : () => string +>'the meaning of life is a number, not a string' : "the meaning of life is a number, not a string" +} + +// Override is not be used on parameters +class RejectWhenOverrideIsOnAParameter { +>RejectWhenOverrideIsOnAParameter : RejectWhenOverrideIsOnAParameter + + public sayHello(override name: string) { return 'hi'; } +>sayHello : (override name: string) => string +>name : string +>'hi' : "hi" +} + +// But can be be used on parameter properties + +abstract class AbstractPropertyBase { +>AbstractPropertyBase : AbstractPropertyBase + + abstract x: number; +>x : number +} +class ConcretePropertyClass extends AbstractPropertyBase { +>ConcretePropertyClass : ConcretePropertyClass +>AbstractPropertyBase : AbstractPropertyBase + + constructor(override x: number) { +>x : number + + super(); +>super() : void +>super : typeof AbstractPropertyBase + } +} + + +// Override is not used on class... +override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } +>RejectWhenOverrideIsOnClassDeclaration : RejectWhenOverrideIsOnClassDeclaration +>sayHello : (name: string) => string +>name : string +>'' : "" + +override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } +>RejectWhenOverrideIsOnInterfaceDeclaration : RejectWhenOverrideIsOnInterfaceDeclaration +>sayHello : (name: string) => any +>name : string + +//... or interface declarations +interface RejectWhenOverrideInAnInterface { +>RejectWhenOverrideInAnInterface : RejectWhenOverrideInAnInterface + + override sayHello(name: string); +>sayHello : (name: string) => any +>name : string +} + +/* Override method should be grouped as consecutive declarations */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { +>RejectWhenOverrideDeclarationsAreNotConsecutive : RejectWhenOverrideDeclarationsAreNotConsecutive +>Base : Base + + override hasOwnProperty(prop: string): boolean { +>hasOwnProperty : (prop: string) => boolean +>prop : string + + return super.hasOwnProperty(prop); +>super.hasOwnProperty(prop) : boolean +>super.hasOwnProperty : (v: string) => boolean +>super : Base +>hasOwnProperty : (v: string) => boolean +>prop : string + } + + public getMeaningOfLife(): number { +>getMeaningOfLife : () => number + + return 42; +>42 : 42 + } + + override propertyIsEnumerable(prop: string): boolean { +>propertyIsEnumerable : (prop: string) => boolean +>prop : string + + return super.propertyIsEnumerable(prop); +>super.propertyIsEnumerable(prop) : boolean +>super.propertyIsEnumerable : (v: string) => boolean +>super : Base +>propertyIsEnumerable : (v: string) => boolean +>prop : string + } +} + diff --git a/tests/baselines/reference/overrideKeywordEs6.errors.txt b/tests/baselines/reference/overrideKeywordEs6.errors.txt index 2596b39a7d978..347b202e43d5d 100644 --- a/tests/baselines/reference/overrideKeywordEs6.errors.txt +++ b/tests/baselines/reference/overrideKeywordEs6.errors.txt @@ -1,8 +1,7 @@ -tests/cases/compiler/overrideKeywordEs6.ts(11,68): error TS1029: 'override' modifier must precede 'async' modifier. +tests/cases/compiler/overrideKeywordEs6.ts(10,68): error TS1029: 'override' modifier must precede 'async' modifier. ==== tests/cases/compiler/overrideKeywordEs6.ts (1 errors) ==== - class Base { async getMeaningOfLife1(): Promise { return Promise.resolve(42); } async getMeaningOfLife2(): Promise { return Promise.reject(42); } diff --git a/tests/baselines/reference/overrideKeywordEs6.js b/tests/baselines/reference/overrideKeywordEs6.js index 150728dc0c74f..96ff0639cd290 100644 --- a/tests/baselines/reference/overrideKeywordEs6.js +++ b/tests/baselines/reference/overrideKeywordEs6.js @@ -1,5 +1,4 @@ //// [overrideKeywordEs6.ts] - class Base { async getMeaningOfLife1(): Promise { return Promise.resolve(42); } async getMeaningOfLife2(): Promise { return Promise.reject(42); } diff --git a/tests/baselines/reference/overrideKeywordEs6.symbols b/tests/baselines/reference/overrideKeywordEs6.symbols new file mode 100644 index 0000000000000..7a70637adbeae --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs6.symbols @@ -0,0 +1,41 @@ +=== tests/cases/compiler/overrideKeywordEs6.ts === +class Base { +>Base : Symbol(Base, Decl(overrideKeywordEs6.ts, 0, 0)) + + async getMeaningOfLife1(): Promise { return Promise.resolve(42); } +>getMeaningOfLife1 : Symbol(Base.getMeaningOfLife1, Decl(overrideKeywordEs6.ts, 0, 12)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + + async getMeaningOfLife2(): Promise { return Promise.reject(42); } +>getMeaningOfLife2 : Symbol(Base.getMeaningOfLife2, Decl(overrideKeywordEs6.ts, 1, 78)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenAsyncPrecedesOverrideModifier extends Base { async override getMeaningOfLife1(): Promise { return Promise.reject(42); }; } +>RejectWhenAsyncPrecedesOverrideModifier : Symbol(RejectWhenAsyncPrecedesOverrideModifier, Decl(overrideKeywordEs6.ts, 3, 1)) +>Base : Symbol(Base, Decl(overrideKeywordEs6.ts, 0, 0)) +>getMeaningOfLife1 : Symbol(RejectWhenAsyncPrecedesOverrideModifier.getMeaningOfLife1, Decl(overrideKeywordEs6.ts, 9, 60)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise.reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>reject : Symbol(PromiseConstructor.reject, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + +class AcceptWhenOverridePrecedesAsyncModifier extends Base { override async getMeaningOfLife2(): Promise { return Promise.resolve(42); }; } +>AcceptWhenOverridePrecedesAsyncModifier : Symbol(AcceptWhenOverridePrecedesAsyncModifier, Decl(overrideKeywordEs6.ts, 9, 146)) +>Base : Symbol(Base, Decl(overrideKeywordEs6.ts, 0, 0)) +>getMeaningOfLife2 : Symbol(AcceptWhenOverridePrecedesAsyncModifier.getMeaningOfLife2, Decl(overrideKeywordEs6.ts, 10, 60)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) +>resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --)) + diff --git a/tests/baselines/reference/overrideKeywordEs6.types b/tests/baselines/reference/overrideKeywordEs6.types new file mode 100644 index 0000000000000..4516edb50522e --- /dev/null +++ b/tests/baselines/reference/overrideKeywordEs6.types @@ -0,0 +1,49 @@ +=== tests/cases/compiler/overrideKeywordEs6.ts === +class Base { +>Base : Base + + async getMeaningOfLife1(): Promise { return Promise.resolve(42); } +>getMeaningOfLife1 : () => Promise +>Promise : Promise +>Promise.resolve(42) : Promise +>Promise.resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>Promise : PromiseConstructor +>resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>42 : 42 + + async getMeaningOfLife2(): Promise { return Promise.reject(42); } +>getMeaningOfLife2 : () => Promise +>Promise : Promise +>Promise.reject(42) : Promise +>Promise.reject : { (reason: any): Promise; (reason: any): Promise; } +>Promise : PromiseConstructor +>reject : { (reason: any): Promise; (reason: any): Promise; } +>42 : 42 +} + +// The expected order of modifiers: +// +// [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier +// +class RejectWhenAsyncPrecedesOverrideModifier extends Base { async override getMeaningOfLife1(): Promise { return Promise.reject(42); }; } +>RejectWhenAsyncPrecedesOverrideModifier : RejectWhenAsyncPrecedesOverrideModifier +>Base : Base +>getMeaningOfLife1 : () => Promise +>Promise : Promise +>Promise.reject(42) : Promise +>Promise.reject : { (reason: any): Promise; (reason: any): Promise; } +>Promise : PromiseConstructor +>reject : { (reason: any): Promise; (reason: any): Promise; } +>42 : 42 + +class AcceptWhenOverridePrecedesAsyncModifier extends Base { override async getMeaningOfLife2(): Promise { return Promise.resolve(42); }; } +>AcceptWhenOverridePrecedesAsyncModifier : AcceptWhenOverridePrecedesAsyncModifier +>Base : Base +>getMeaningOfLife2 : () => Promise +>Promise : Promise +>Promise.resolve(42) : Promise +>Promise.resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>Promise : PromiseConstructor +>resolve : { (value: T | PromiseLike): Promise; (): Promise; } +>42 : 42 + diff --git a/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js b/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js index 8d91090453b8a..8394371f9081a 100644 --- a/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js +++ b/tests/baselines/reference/transpile/Supports setting noImplicitOverride.js @@ -1,3 +1,2 @@ -"use strict"; x; //# sourceMappingURL=input.js.map \ No newline at end of file diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index 25a2c11d33fd4..69d55b1ea1cf0 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index d6534c834a1cb..8168360cdfa8a 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index 414f3b579031a..a0da19ba50fc7 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index 940970d297f5e..be732a2868302 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index 074f24cad5d8b..1de64568039f4 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 25a2c11d33fd4..69d55b1ea1cf0 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index a5eae1a465783..ef4ffbbefcc99 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index 2468ac7921b8e..c3b7a73a12ea3 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -21,6 +21,7 @@ /* Strict Type-Checking Options */ "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "noImplicitOverride": true, /* Raise error when inherited/overridden class members are not explicitly marked 'override' */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ From 489d09c5b7774fbf8e54c5ae91b100ad2a879ecf Mon Sep 17 00:00:00 2001 From: Paul Cody Johnston Date: Sun, 3 Dec 2017 13:10:01 -0700 Subject: [PATCH 9/9] Include override as valid parameter property --- src/compiler/checker.ts | 96 +++--- src/compiler/types.ts | 2 +- src/compiler/utilities.ts | 2 +- tests/cases/compiler/noImplicitOverride.ts | 222 +++++++------ tests/cases/compiler/overrideKeywordEs5.ts | 350 ++++++++++++++++----- tests/cases/compiler/overrideKeywordEs6.ts | 13 +- 6 files changed, 456 insertions(+), 229 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b008c19ab6102..06dc8b14742e8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -19765,11 +19765,6 @@ namespace ts { checkDecorators(node); - // TODO(pcj): @andy-ms says remove this - if (getModifierFlags(node) & ModifierFlags.Override) { - checkOverrideDeclaration(node); - } - checkSignatureDeclaration(node); if (node.kind === SyntaxKind.GetAccessor) { if (!(node.flags & NodeFlags.Ambient) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) { @@ -19816,17 +19811,6 @@ namespace ts { checkSourceElement(node.body); registerForUnusedIdentifiersCheck(node); - -/* - // TODO(pcj): Document what this is doing - if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) { - checkSourceElement(node.body); - registerForUnusedIdentifiersCheck(node); - } - else { - checkNodeDeferred(node); - } - */ } function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) { @@ -22668,7 +22652,7 @@ namespace ts { typeToString(getTypeOfSymbol(foundSymbol)) ); } - diagnostics.add(createDiagnosticForNodeFromMessageChain(getDeclarationName(derived.valueDeclaration), errorInfo)); + diagnostics.add(createDiagnosticForNodeFromMessageChain(symbol.valueDeclaration, errorInfo)); } } // No matching property found on the object type. It @@ -25371,7 +25355,7 @@ namespace ts { return quickResult; } - let lastStatic: Node, lastDeclare: Node, lastAsync: Node, lastReadonly: Node; + let lastStatic: Node, lastDeclare: Node, lastAsync: Node, lastReadonly: Node, lastOverride: Node; let flags = ModifierFlags.None; for (const modifier of node.modifiers) { if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { @@ -25539,40 +25523,46 @@ namespace ts { flags |= ModifierFlags.Abstract; break; - case SyntaxKind.OverrideKeyword: - if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); - } - else if (flags & ModifierFlags.Static) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "static"); - } - else if (flags & ModifierFlags.Async) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); - } - else if (flags & ModifierFlags.Readonly) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); - } - else if (flags & ModifierFlags.Abstract) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override"); - } - else if (flags & ModifierFlags.Private) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); - } - else if (node.kind === SyntaxKind.Parameter) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "override"); - } - else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override"); - } - else if (node.kind !== SyntaxKind.MethodDeclaration && - node.kind !== SyntaxKind.PropertyDeclaration && - node.kind !== SyntaxKind.GetAccessor && - node.kind !== SyntaxKind.SetAccessor) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_class_method_or_property_declaration, "override"); - } - - flags |= ModifierFlags.Override; - break; + case SyntaxKind.OverrideKeyword: + if (flags & ModifierFlags.Override) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override"); + } + else if (flags & ModifierFlags.Static) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "static"); + } + else if (flags & ModifierFlags.Async) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "async"); + } + else if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "override", "readonly"); + } + else if (flags & ModifierFlags.Abstract) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override"); + } + else if (flags & ModifierFlags.Private) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override"); + } + else if (node.kind === SyntaxKind.Parameter) { + // Reject override for all non-parameter properties. Additional validation of + // parameter properties exists elsewhere in the codebase. + if (node.parent.kind !== SyntaxKind.Constructor) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "override"); + } + } + + else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override"); + } + else if (node.kind !== SyntaxKind.MethodDeclaration && + node.kind !== SyntaxKind.PropertyDeclaration && + node.kind !== SyntaxKind.GetAccessor && + node.kind !== SyntaxKind.SetAccessor) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_class_method_or_property_declaration, "override"); + } + + flags |= ModifierFlags.Override; + lastOverride = modifier; + break; case SyntaxKind.AsyncKeyword: if (flags & ModifierFlags.Async) { @@ -25601,7 +25591,7 @@ namespace ts { return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async"); } else if (flags & ModifierFlags.Override) { - return grammarErrorOnNode(lastReadonly, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); + return grammarErrorOnNode(lastOverride, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); } else if (flags & ModifierFlags.Readonly) { return grammarErrorOnNode(lastReadonly, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "readonly"); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 140cff0965469..9b9a813e552f1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -504,7 +504,7 @@ namespace ts { AccessibilityModifier = Public | Private | Protected, // Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property. - ParameterPropertyModifier = AccessibilityModifier | Readonly, + ParameterPropertyModifier = AccessibilityModifier | Readonly | Override, NonPublicAccessibilityModifier = Private | Protected, TypeScriptModifier = Ambient | Public | Private | Protected | Override | Readonly | Abstract | Const, diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2b5e0601562e8..694d3c0ff3962 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -666,7 +666,7 @@ namespace ts { // construct. return getSpanOfTokenAtPosition(sourceFile, node.pos); } - + const pos = nodeIsMissing(errorNode) ? errorNode.pos : skipTrivia(sourceFile.text, errorNode.pos); diff --git a/tests/cases/compiler/noImplicitOverride.ts b/tests/cases/compiler/noImplicitOverride.ts index 366309f11435d..c973b77a85c07 100644 --- a/tests/cases/compiler/noImplicitOverride.ts +++ b/tests/cases/compiler/noImplicitOverride.ts @@ -1,140 +1,176 @@ // @noImplicitOverride: true // @target: es5 -// ****************************************************** -// First set of cases deal with inheritance from Object. -// ****************************************************** +// ============================================================== +// Utility classes used in later test sections +// ============================================================== -class RejectWhenOverrideAbsentOnInheritedMethod extends Object { - toString(): string { return 'foo'; }; -} -class AcceptWhenOverridePresentOnInheritedMethod extends Object { - override toString(): string { return 'foo'; }; -} +class StaticBase { + static id: number = 1; -// Similar to previous cases where augmentation from Object is implicit -class RejectWhenOverrideAbsentOnAugmentedProperty { - toString(): string { return 'foo'; }; -} -class AcceptWhenOverridePresentOnAugumentedProperty extends Object { - override toString(): string { return 'foo'; }; + static toStringStatic(): string { + return ''; + } } -// This should fail via type mismatch of the return value. -// (test is not specific to the override checking code) -class RejectWhenOverrideTypeMismatchOnMethodThatMasksObjectTypeMember { - toString(): number { - return -1; +class InstanceBase { + public publicId: number = 1; + protected protectedId: number = 1; + private privateId: number = 1; + + public toStringPublic(): string { + return ''; } -} -// ****************************************************** -// Next set of cases deal with inheritance derived from -// an explicitly defined class. -// ****************************************************** + protected toStringProtected(): string { + return ''; + } -class Base { - // Public property - public userId: number = 1; - // Accessor - get name(): string { return 'Base'; } - // Typical public method - getMeaningOfLife(): number { return 42; } - // Private method - private processInternal(): void { } + private toStringPrivate(): string { + return ''; + } } -class RejectWhenOverrideAbsentOnInheritedProperty extends Base { - public userId = 2; +class ReadonlyBase { + readonly id: number; } -class AcceptWhenOverridePresentOnInheritedProperty extends Base { - public override userId = 2; + +class OptionalBase { + readonly id?: number; } -class RejectWhenOverrideAbsentOnInheritedAccessor extends Base { - get name(): string { return 'foo'; }; +class AccessorBase { + get id(): number { return 1; } + set id(id: number) {} } -class AcceptWhenOverridePresentOnInheritedAccessor extends Base { - override get name(): string { return 'foo'; }; + +abstract class AbstractBase { + abstract id: number; + abstract toStringAbstract(): string; } -class RejectWhenOverrideAbsentOnInheritedMethod extends Base { - getMeaningOfLife(): number { return 24; }; +const mixin = {}>(Base: BC) => class extends Base { + mixedIn() {} +}; + +class MixinBase { + normal() {} } -class AcceptWhenOverridePresentOnInheritedMethod extends Base { - override getMeaningOfLife(): number { return 24; }; + +class DerivedBase extends InstanceBase { } -class RejectWhenOverridePresentWithPrivateModifier extends Base { - private override processInternal() { } +interface InterfaceBase { + id: number; + toStringInterface(): string; } -// ****************************************************** -// Next set of cases deal with override within interfaces -// and abstract classes (where is should not be present). -// ****************************************************** +interface IndexSignature { + [key: string]: string +} -interface Shape { - getWidth(): number; +// Override must be marked for properties augmented from Object, either +// implicitly, explicity, or though a derived class +class RejectWhenOverrideAbsentOnAugmentedPropertyImplicit { + toString(): string { return ''; } +} +class RejectWhenOverrideAbsentOnAugmentedPropertyExplicit extends Object { + toString(): string { return ''; } +} +class RejectWhenOverrideAbsentOnAugmentedPropertyDerived extends DerivedBase { + toString(): string { return ''; } } -interface RejectWhenOverridePresentOnInterfaceDeclaration extends Shape { - override getWidth(): number; +// Override must be marked for properties inherited from base class, +class RejectWhenOverrideAbsentOnInheritedMember extends InstanceBase { + protected protectedId: number; + public publicId: number; + protected toStringProtected(): string { return ''; } + public toStringPublic(): string { return ''; } } -interface AcceptWhenOverrideAbsentOnInterfaceDeclaration extends Shape { - getWidth(): number; +// Override must be marked for properties inherited from base class (accessor +// variant) +class RejectWhenOverrideAbsentOnInheritedAccessorMember extends AccessorBase { + get id(): number { return 2; } + set id(id: number) {} } -// ****************************************************** -// Next set of cases deal with override with abstract -// classes. -// ****************************************************** +// Override must be marked for properties inherited from base class (static +// variant) +class RejectWhenOverrideAbsentOnInheritedStaticMember extends StaticBase { + static id: number = 2; + static toStringStatic(): string { return ''; } +} -abstract class Animal { - protected readonly name: string +// Override must be marked for properties inherited from base class (readonly +// variant) +class RejectWhenOverrideAbsentOnInheritedReadonlyMember extends ReadonlyBase { + readonly id: number = 2; + toStringReadonly(): string { return ''; } +} - constructor(name: string) { - this.name = name; - } +// Override must be marked for a things that implement an abstract superclass +// member +class RejectWhenOverrideAbsentOnImplementationOfAbstractMember extends AbstractBase { + id: number = 1; + toStringAbstract(): string { return ''; } +} - abstract speak(): string; +// Override must be marked on a method that implements an abstract method, even +// if that class is itself abstract. +abstract class RejectWhenOverrideAbsentOnImplementationOfAbstractMemberInAbstractClass extends AbstractBase { + toStringAbstract(): string { return ''; } } -abstract class RejectWhenOverridePresentWithAbstractModifier extends Animal { - abstract override speak(): string; +// Override must be marked on methods inherited via normal semantics and via the +// mixin class. +class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(MixinBase) { + normal() {} + mixedIn() {} } -abstract class AcceptWhenOverridePresentOnConcreteDeclaration extends Animal { - override speak(): string { return "Woof!"; } +// Override must be marked on parameter properties that implement an abstract +// property. In this case, the 'public' modifier informs the compiler that 'id' +// is a parameter property. This puts the 'id' symbol in the instance member +// symbol table and thus exposes it to the codepath that checks for missing +// override members. +class RejectWhenOverrideAbsentOnParameterPropertyThatImplementsSuperclassMember extends AbstractBase { + constructor(public id: number) { + super(); + } + override toStringAbstract(): string { return 'concrete'; } } -// ****************************************************** -// Next set of cases deal with override with mixins -// ****************************************************** -const mixin = {}>(Base: BC) => class extends Base { - mixedIn() {} -}; +// Override *should* be marked on all parameter properties that implement some +// an abstract member. In this case, there is no additional modifier on the 'id' +// symbol that flags it as a parameter property (i.e., the symbol is considered +// to be a local to the scope of the constructor function). In this case, it is +// correct for the compiler *not* to raise an error (otherwise a user would +// never be able to name a constructor parameter as that of an abstract +// superclass member!). +class AcceptWhenOverrideAbsentOnConstructorParameterThatIsNotAParameterProperty extends AbstractBase { + constructor(id: number) { + super(); + } + override id: number = 2; + override toStringAbstract(): string { return 'concrete'; } +} class A { - normal() {} -} + "constructor": typeof A; // Explicitly declare constructor property + protected static type: string; -class RejectWhenOverrideAbsentOnInheritedMethodMixin extends mixin(A) { - normal() {} - mixedIn() {} + public log() { + console.log(this.constructor.type); // Access actual constructor object + } } -class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(A) { - override normal() {} - override mixedIn() {} +class B extends A { + protected static type: string = 'B'; } -// ******************************************************** -// Next set of cases deal with override specified via JsDoc -// ******************************************************** - -//class AcceptWhenOverrideSpecifiedByJSDocAnnotation extends Animal { -// /** @override */ public speak(): string { return "Woof!" } -//} +class C extends A { + protected static type: string = 'C'; +} \ No newline at end of file diff --git a/tests/cases/compiler/overrideKeywordEs5.ts b/tests/cases/compiler/overrideKeywordEs5.ts index bb0411baa5612..8f08fed4f4f03 100644 --- a/tests/cases/compiler/overrideKeywordEs5.ts +++ b/tests/cases/compiler/overrideKeywordEs5.ts @@ -2,137 +2,335 @@ // @noImplicitOverride: false // @target: es5 +// ============================================================== +// Utility classes used in later test sections +// ============================================================== + +class StaticBase { + static id: number = 1; + + static toStringStatic(): string { + return ''; + } +} + +class InstanceBase { + public publicId: number = 1; + protected protectedId: number = 1; + private privateId: number = 1; + + public toStringPublic(): string { + return ''; + } + + protected toStringProtected(): string { + return ''; + } + + private toStringPrivate(): string { + return ''; + } +} + +class ReadonlyBase { + readonly id: number; +} + +class OptionalBase { + readonly id?: number; +} + +class AccessorBase { + get id(): number { return 1; } + set id(id: number) {} +} + abstract class AbstractBase { - readonly id: string; - public wasDisposed?: boolean; - private name_: string; - get name() { return this.name_; } - set name(name: string) { this.name_ = name; } - - static toStringStatic(): string { return 'static'; } - public toStringPublic(): string { return 'public'; }; - protected toStringProtected(): string { return 'protected'; } - private toStringPrivate(): string { return 'private'; } - private toStringPrivate2(): string { return 'private2'; } + abstract id: number; abstract toStringAbstract(): string; - abstract toStringAbstract2(): string; +} + +const mixin = {}>(Base: BC) => class extends Base { + mixedIn() {} +}; + +class MixinBase { + normal() {} +} - getMeaningOfLife(): number { return 42; } +class DerivedBase extends InstanceBase { } -class Base extends AbstractBase { - override toStringAbstract(): string { return 'implemented'; } - override toStringAbstract2(): string { return 'implemented2'; } +interface InterfaceBase { + id: number; + toStringInterface(): string; } -// The expected order of modifiers: +interface IndexSignature { + [key: string]: string +} + +// ============================================================== +// Tests that deal with modifier ordering +// ============================================================== + +// Expected order of modifiers: // // [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier // -class RejectWhenOverridePrecedesPublicModifier extends Base { override public toStringPublic() { return ''; }; } -class RejectWhenOverridePrecedesProtectedModifier extends Base { override protected toStringProtected() { return ''; }; } -class RejectWhenStaticPrecedesOverrideModifier extends Base { static override toStringStatic() { return ''; }; } -class AcceptWhenOverrideFollowsAccessModifier extends Base { public override toStringPublic() { return ''; } } -class RejectWhenReadonlyPrecedesOverrideModifier extends Base { readonly override id: string; } -// Modifiers should never be repeated -class RejectWhenOverrideIsRepeated extends Base { - public override override toStringPublic() { return ''; } +// Override should not be repeated +class RejectWhenOverrideIsRepeated extends InstanceBase { + override override toStringPublic() { return ''; } } -// You cannot override a private method -class RejectWhenOverridePrivateMethod extends Base { +// Override should not be present on private members +class RejectWhenOverrideOnPrivateMethod extends InstanceBase { + private override privateId = 2; private override toStringPrivate() { return ''; } - override private toStringPrivate2() { return ''; } } -// Override and abstract on methods are orthogonal, should never be used together -abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { - abstract override toStringAbstract(): string; - override abstract toStringAbstract2(): string; +// override should follow protected +class RejectWhenOverridePrecedesProtectedModifier extends InstanceBase { + override protected protectedId: number; + override protected toStringProtected() { return ''; }; +} +class AcceptWhenOverrideSuccedesProtectedModifier extends InstanceBase { + protected override protectedId: number; + protected override toStringProtected() { return ''; }; } -// Acceptable to provide an override implementation in an abstract class however -abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { - override toStringAbstract(): string { return 'implemented in abstract class'; } +// override should follow public +class RejectWhenOverridePrecedesPublicModifier extends InstanceBase { + override public publicId: number; + override public toStringPublic() { return ''; }; +} +class AcceptWhenOverrideSuccedesPublicModifier extends InstanceBase { + public override publicId: number; + public override toStringPublic() { return ''; }; } -// Override checks are allowed on static methods -class AcceptWhenOverrideStaticMethod extends Base { - override static toStringStatic() { return 'static'; } +// override should go before static +class RejectWhenStaticPrecedesOverrideModifier extends StaticBase { + static override id: number = 2; + static override toStringStatic() { return ''; }; +} +class AcceptWhenStaticSuccedesOverrideModifier extends StaticBase { + override static id: number = 2; + override static toStringStatic() { return ''; }; } -// Compiler already checks for access modifier narrowing, -// override does not alter these semantics. -class RejectWhenOverrideChangesAccessModifier extends Base { - protected override static toStringStatic() { return 'member is now protected'; } +// override should go before readonly +class RejectWhenReadonlyPrecedesOverrideModifier extends ReadonlyBase { + readonly override id: number; +} +class AcceptWhenReadonlySuccedesOverrideModifier extends ReadonlyBase { + override readonly id: number; } -// Compiler should be able to traverse multiple levels of inheritance -// to assess for overriden members (already does this). -class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends Base { - override getMeaningOfLife(): number { return 12; } +// Compiler already checks for access modifier narrowing +// (override does not alter these semantics). +class RejectWhenOverrideChangesAccessModifier extends StaticBase { + protected override static toStringStatic() { return 'was public'; } } +// ============================================================== +// Tests that deal with optional properties +// ============================================================== + // Override cannot be used with optional property. -class RejectWhenOverrideOptionalProperty extends Base { - public override wasDisposed?: boolean; +class RejectWhenOverrideOptionalProperty extends OptionalBase { + override id?: number; } +// ============================================================== +// Tests that deal with get/set accessors +// ============================================================== + // If one accessor is marked override, they both should be. -class RejectWhenAccessorNotBothOverride extends Base { - override get name() { return ''; } - /* */ set name(n: string) {} +class RejectWhenAccessorNotBothOverride extends AccessorBase { + override get id() { return 2; } + /* */ set id(id: number) {} +} + +// Compiler should be satisfied if both override present and correct +class AcceptWhenAccessorBothOverrideSuperclass extends AccessorBase { + override get id() { return 2; } + override set id(id: number) {} +} + +// Compiler should error if try to override accessor incorrectly +class RejectWhenAccessorBothOverrideButNotPresentInSuperclass extends AccessorBase { + override get iDontExist() { return 2; } + override set iDontExist(id: number) {} +} + +abstract class HalfAccessorImplementation extends AbstractBase { + override get id(): number { return 2; } +} + +class AcceptWhenOverridePresentOnOtherHalfInSubclass extends HalfAccessorImplementation { + override set id(id: number) {} + toStringAbstract(): string { return ''; } } +// This one should be tested in 'noImplicitOverride' +class RejectWhenOverrideAbsentOnOtherHalfInSubclass extends HalfAccessorImplementation { + set id(id: number) {} + toStringAbstract(): string { return ''; } +} + +// ============================================================== +// Tests that deal with inheritance detection +// ============================================================== + // Compiler should detect when override member is not inherited or augmented -class RejectWhenOverrideMarkedOnNonInheritedMember extends Base { - public override iDontExist() { return ''; } +class RejectWhenOverrideMarkedOnNonInheritedMember extends InstanceBase { + override iDontExist(): string { return ''; } +} + +// Compiler should be able to traverse multiple levels of inheritance +// to assess for overriden members (already does this). +class AcceptWhenOverrideMemberExistsOnNonImmediateSuperclass extends DerivedBase { + override toStringPublic(): string { return ''; } } // Compiler already detects overriden assignability mismatches, // override keyword does not change these semantics -class RejectWhenOverrideHasMismatchedType extends Base { - override getMeaningOfLife(): string { return 'the meaning of life is a number, not a string'; } +class RejectWhenOverrideHasMismatchedType extends InstanceBase { + override toStringPublic(): number { return 1; } +} + +// Override is compatible with properties augmented from Object, +// either implicitly, explicity, or though a derived class +class AcceptWhenOverridePresentOnAugmentedPropertyImplicit { + override toString(): string { return ''; } } +class AcceptWhenOverridePresentOnAugmentedPropertyExplicit extends Object { + override toString(): string { return ''; } +} +class AcceptWhenOverridePresentOnAugmentedPropertyDerived extends DerivedBase { + override toString(): string { return ''; } +} + +// ============================================================== +// Tests that deal with parameters +// ============================================================== -// Override is not be used on parameters +// Override is not used on regular function/method parameters class RejectWhenOverrideIsOnAParameter { public sayHello(override name: string) { return 'hi'; } } -// But can be be used on parameter properties +// Override *can* be used on parameter properties though +class AcceptWhenOverrideOnParameterPropertyImplementsRequiredMember extends AbstractBase { + constructor(override id: number) { + super(); + } + toStringAbstract(): string { return 'concrete'; } +} -abstract class AbstractPropertyBase { - abstract x: number; +// Override *can* be used on parameter properties in conjuction with other +// parameter property modifiers +class AcceptWhenOverrideOnParameterPropertyWithAdditionalModifiers extends AbstractBase { + constructor(public override id: number) { + super(); + } + toStringAbstract(): string { return 'concrete'; } } -class ConcretePropertyClass extends AbstractPropertyBase { - constructor(override x: number) { + +class RejectWhenOverridePresentOnConstructorOverloadDeclaration extends AbstractBase { + constructor(override id: number); + constructor(override id: number, public name?: string) { super(); } + override toStringAbstract(): string { return 'concrete'; } } +// But it should be an error to 'override' a parameter property that does not +// actually do so. +class RejectWhenOverrideOnParameterPropertyDoesNotImplementRequiredMember extends AbstractBase { + constructor(override id: number, override iDontExist: number) { + super(); + } + toStringAbstract(): string { return 'concrete'; } +} -// Override is not used on class... -override class RejectWhenOverrideIsOnClassDeclaration { public sayHello(name: string) { return ''; } } -override interface RejectWhenOverrideIsOnInterfaceDeclaration { sayHello(name: string); } +// ============================================================== +// Tests that deal with override in spurious locations +// ============================================================== -//... or interface declarations -interface RejectWhenOverrideInAnInterface { - override sayHello(name: string); +// Override is not used on class or interface declarations +override class RejectWhenOverrideIsOnClassDeclaration { +} +override interface RejectWhenOverrideIsOnInterfaceDeclaration { } -/* Override method should be grouped as consecutive declarations */ -class RejectWhenOverrideDeclarationsAreNotConsecutive extends Base { - override hasOwnProperty(prop: string): boolean { - return super.hasOwnProperty(prop); +// Override is not used on constructor declarations. +// One *could* make an argument that this is semantically correct though. +class RejectWhenOverridePresentOnConstructorDeclaration extends InstanceBase { + override constructor() { + super(); } +} - public getMeaningOfLife(): number { - return 42; - } +// Override is not used on index signature declarations +// Wait, should it? If this is the point of the implementation, +// then maybe is should be. Somewhat esoteric though. +// @see https://stackoverflow.com/questions/31977481/can-i-define-a-typescript-class-which-has-an-index-signature +class RejectWhenOverridePresentOnIndexSignatureDeclaration implements IndexSignature { + override [key: string]: string; +} + +// Override is not used on object literals. +// One could make an argument that is should be, +// but since no modifiers are allowed here +// we don't need to bend over backwards to support it. +let rejectWhenOverridePresentOnObjectLiteral = { + override toString(): string { return ''; } +} + +// ============================================================== +// Tests that deal with interfaces and abstract classes +// ============================================================== + +// Acceptable to provide an override implementation in an abstract class however +abstract class AcceptWhenOverrideInAbstractClass extends AbstractBase { + override toStringAbstract(): string { return 'now concrete'; } +} + +// Override and abstract on methods are orthogonal, should never be used together +abstract class RejectWhenOverrideAbstractMethod extends AbstractBase { + override abstract toStringAbstract(): string; +} + +// Override should not be used/required in interface declarations +// Override errors are only triggered in concrete locations, +// so there's no need to say 'override' here. +interface RejectWhenOverrideInAnInterface extends InterfaceBase { + override toStringInterface(): string; +} + +// ============================================================== +// Tests that deal with mixin classes +// ============================================================== + +class AcceptWhenOverridePresentOnInheritedMethodMixin extends mixin(MixinBase) { + override normal() {} + override mixedIn() {} +} + +// ============================================================== +// Tests that deal with grouping of override declarations +// ============================================================== + +/* Override method should be grouped as consecutive declarations */ +class RejectWhenOverrideDeclarationsAreNotConsecutive extends InstanceBase { + public override toStringPublic(): string { return '' } - override propertyIsEnumerable(prop: string): boolean { - return super.propertyIsEnumerable(prop); + public iShouldNotBreakUpConsecutiveOverrideDeclarations(): boolean { + return true; } + protected override toStringProtected(): string { return '' } + } diff --git a/tests/cases/compiler/overrideKeywordEs6.ts b/tests/cases/compiler/overrideKeywordEs6.ts index a6f3d6a530034..31fa1eefa857e 100644 --- a/tests/cases/compiler/overrideKeywordEs6.ts +++ b/tests/cases/compiler/overrideKeywordEs6.ts @@ -2,14 +2,17 @@ // @noImplicitOverride: false // @target: es6 -class Base { - async getMeaningOfLife1(): Promise { return Promise.resolve(42); } - async getMeaningOfLife2(): Promise { return Promise.reject(42); } +class AsyncBase { + async toStringAsync(): Promise { return Promise.resolve(''); } } // The expected order of modifiers: // // [public | protected | private] [abstract | override] [static] [readonly | async] [get | set] identifier // -class RejectWhenAsyncPrecedesOverrideModifier extends Base { async override getMeaningOfLife1(): Promise { return Promise.reject(42); }; } -class AcceptWhenOverridePrecedesAsyncModifier extends Base { override async getMeaningOfLife2(): Promise { return Promise.resolve(42); }; } +class RejectWhenAsyncPrecedesOverrideModifier extends AsyncBase { + async override toStringAsync(): Promise { return Promise.resolve(''); } +} +class AcceptWhenOverridePrecedesAsyncModifier extends AsyncBase { + override async toStringAsync(): Promise { return Promise.resolve(''); } +}