diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1b6b31f958697..6445f8b13dec1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -532,7 +532,7 @@ namespace ts { } // Because of module/namespace merging, a module's exports are in scope, - // yet we never want to treat an export specifier as putting a member in scope. + // yet we never want to treat an export specifier as putting a member in scope. // Therefore, if the name we find is purely an export specifier, it is not actually considered in scope. // Two things to note about this: // 1. We have to check this without calling getSymbol. The problem with calling getSymbol @@ -11398,7 +11398,7 @@ namespace ts { // we can get here in two cases // 1. mixed static and instance class members // 2. something with the same name was defined before the set of overloads that prevents them from merging - // here we'll report error only for the first case since for second we should already report error in binder + // here we'll report error only for the first case since for second we should already report error in binder if (reportError) { const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static; error(errorNode, diagnostic); @@ -12065,8 +12065,8 @@ namespace ts { const symbol = getSymbolOfNode(node); const localSymbol = node.localSymbol || symbol; - // Since the javascript won't do semantic analysis like typescript, - // if the javascript file comes before the typescript file and both contain same name functions, + // Since the javascript won't do semantic analysis like typescript, + // if the javascript file comes before the typescript file and both contain same name functions, // checkFunctionOrConstructorSymbol wouldn't be called if we didnt ignore javascript function. const firstDeclaration = forEach(localSymbol.declarations, // Get first non javascript function declaration @@ -16227,11 +16227,17 @@ namespace ts { if (checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_an_interface_must_directly_refer_to_a_built_in_symbol)) { return true; } + if (node.initializer) { + return grammarErrorOnNode(node.initializer, Diagnostics.An_interface_property_cannot_have_an_initializer); + } } else if (node.parent.kind === SyntaxKind.TypeLiteral) { if (checkGrammarForNonSymbolComputedProperty(node.name, Diagnostics.A_computed_property_name_in_a_type_literal_must_directly_refer_to_a_built_in_symbol)) { return true; } + if (node.initializer) { + return grammarErrorOnNode(node.initializer, Diagnostics.A_type_literal_property_cannot_have_an_initializer); + } } if (isInAmbientContext(node) && node.initializer) { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 5b70c70ae4b83..cd2fa76953693 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -783,6 +783,14 @@ "category": "Error", "code": 1245 }, + "An interface property cannot have an initializer.": { + "category": "Error", + "code": 1246 + }, + "A type literal property cannot have an initializer.": { + "category": "Error", + "code": 1247 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", @@ -2418,7 +2426,7 @@ "Not all code paths return a value.": { "category": "Error", "code": 7030 - }, + }, "You cannot rename this element.": { "category": "Error", "code": 8000 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 212594f7b7dbd..f4ac49a6b6fba 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2247,6 +2247,14 @@ namespace ts { property.name = name; property.questionToken = questionToken; property.type = parseTypeAnnotation(); + + if (token === SyntaxKind.EqualsToken) { + // Although type literal properties cannot not have initializers, we attempt + // to parse an initializer so we can report in the checker that an interface + // property or type literal property cannot have an initializer. + property.initializer = parseNonParameterInitializer(); + } + parseTypeMemberSemicolon(); return finishNode(property); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9edd7654b6b47..58250c9dc5ee9 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -586,6 +586,7 @@ namespace ts { name: PropertyName; // Declared property name questionToken?: Node; // Present on optional property type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer } // @kind(SyntaxKind.PropertyDeclaration) diff --git a/tests/baselines/reference/errorOnInitializerInInterfaceProperty.errors.txt b/tests/baselines/reference/errorOnInitializerInInterfaceProperty.errors.txt new file mode 100644 index 0000000000000..03e899e7c2dee --- /dev/null +++ b/tests/baselines/reference/errorOnInitializerInInterfaceProperty.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/errorOnInitializerInInterfaceProperty.ts(2,19): error TS1246: An interface property cannot have an initializer. + + +==== tests/cases/compiler/errorOnInitializerInInterfaceProperty.ts (1 errors) ==== + interface Foo { + bar: number = 5; + ~ +!!! error TS1246: An interface property cannot have an initializer. + } + \ No newline at end of file diff --git a/tests/baselines/reference/errorOnInitializerInInterfaceProperty.js b/tests/baselines/reference/errorOnInitializerInInterfaceProperty.js new file mode 100644 index 0000000000000..c40a3cfb43d19 --- /dev/null +++ b/tests/baselines/reference/errorOnInitializerInInterfaceProperty.js @@ -0,0 +1,7 @@ +//// [errorOnInitializerInInterfaceProperty.ts] +interface Foo { + bar: number = 5; +} + + +//// [errorOnInitializerInInterfaceProperty.js] diff --git a/tests/baselines/reference/errorOnInitializerInObjectTypeLiteralProperty.errors.txt b/tests/baselines/reference/errorOnInitializerInObjectTypeLiteralProperty.errors.txt new file mode 100644 index 0000000000000..f6d10b92b2d8f --- /dev/null +++ b/tests/baselines/reference/errorOnInitializerInObjectTypeLiteralProperty.errors.txt @@ -0,0 +1,17 @@ +tests/cases/compiler/errorOnInitializerInObjectTypeLiteralProperty.ts(2,19): error TS1247: A type literal property cannot have an initializer. +tests/cases/compiler/errorOnInitializerInObjectTypeLiteralProperty.ts(6,19): error TS1247: A type literal property cannot have an initializer. + + +==== tests/cases/compiler/errorOnInitializerInObjectTypeLiteralProperty.ts (2 errors) ==== + var Foo: { + bar: number = 5; + ~ +!!! error TS1247: A type literal property cannot have an initializer. + }; + + let Bar: { + bar: number = 5; + ~ +!!! error TS1247: A type literal property cannot have an initializer. + }; + \ No newline at end of file diff --git a/tests/baselines/reference/errorOnInitializerInObjectTypeLiteralProperty.js b/tests/baselines/reference/errorOnInitializerInObjectTypeLiteralProperty.js new file mode 100644 index 0000000000000..4dcc0b7dce67c --- /dev/null +++ b/tests/baselines/reference/errorOnInitializerInObjectTypeLiteralProperty.js @@ -0,0 +1,13 @@ +//// [errorOnInitializerInObjectTypeLiteralProperty.ts] +var Foo: { + bar: number = 5; +}; + +let Bar: { + bar: number = 5; +}; + + +//// [errorOnInitializerInObjectTypeLiteralProperty.js] +var Foo; +var Bar; diff --git a/tests/cases/compiler/errorOnInitializerInInterfaceProperty.ts b/tests/cases/compiler/errorOnInitializerInInterfaceProperty.ts new file mode 100644 index 0000000000000..ac600103e7252 --- /dev/null +++ b/tests/cases/compiler/errorOnInitializerInInterfaceProperty.ts @@ -0,0 +1,3 @@ +interface Foo { + bar: number = 5; +} diff --git a/tests/cases/compiler/errorOnInitializerInObjectTypeLiteralProperty.ts b/tests/cases/compiler/errorOnInitializerInObjectTypeLiteralProperty.ts new file mode 100644 index 0000000000000..a02f8b0f709a1 --- /dev/null +++ b/tests/cases/compiler/errorOnInitializerInObjectTypeLiteralProperty.ts @@ -0,0 +1,7 @@ +var Foo: { + bar: number = 5; +}; + +let Bar: { + bar: number = 5; +};