diff --git a/crates/oxc_ast/src/ast_impl/js.rs b/crates/oxc_ast/src/ast_impl/js.rs index ce40ea6713ab9..10e064ad8f336 100644 --- a/crates/oxc_ast/src/ast_impl/js.rs +++ b/crates/oxc_ast/src/ast_impl/js.rs @@ -448,6 +448,15 @@ impl<'a> PropertyKey<'a> { } } +impl PropertyKind { + /// Returns `true` if this property is a getter or setter. + /// + /// Analogous to [`MethodDefinitionKind::is_accessor`]. + pub fn is_accessor(self) -> bool { + matches!(self, Self::Get | Self::Set) + } +} + impl<'a> TemplateLiteral<'a> { pub fn is_no_substitution_template(&self) -> bool { self.expressions.is_empty() && self.quasis.len() == 1 @@ -1424,6 +1433,8 @@ impl MethodDefinitionKind { } /// Returns `true` if this method is a getter or a setter. + /// + /// Analogous to [`PropertyKind::is_accessor`]. pub fn is_accessor(&self) -> bool { matches!(self, Self::Get | Self::Set) } diff --git a/crates/oxc_semantic/src/checker/mod.rs b/crates/oxc_semantic/src/checker/mod.rs index db259831c6a6e..59284e1964497 100644 --- a/crates/oxc_semantic/src/checker/mod.rs +++ b/crates/oxc_semantic/src/checker/mod.rs @@ -77,7 +77,10 @@ pub fn check<'a>(node: &AstNode<'a>, ctx: &SemanticBuilder<'a>) { ts::check_method_definition(method, ctx); } AstKind::PropertyDefinition(prop) => ts::check_property_definition(prop, ctx), - AstKind::ObjectProperty(prop) => js::check_object_property(prop, ctx), + AstKind::ObjectProperty(prop) => { + js::check_object_property(prop, ctx); + ts::check_object_property(prop, ctx); + } AstKind::Super(sup) => js::check_super(sup, node, ctx), AstKind::FormalParameters(params) => { diff --git a/crates/oxc_semantic/src/checker/typescript.rs b/crates/oxc_semantic/src/checker/typescript.rs index 9422d00d7ac8e..da7dee513d528 100644 --- a/crates/oxc_semantic/src/checker/typescript.rs +++ b/crates/oxc_semantic/src/checker/typescript.rs @@ -359,3 +359,13 @@ pub fn check_property_definition<'a>(prop: &PropertyDefinition<'a>, ctx: &Semant ctx.error(abstract_property_cannot_have_initializer(prop_name, span)); } } + +pub fn check_object_property(prop: &ObjectProperty, ctx: &SemanticBuilder<'_>) { + if let Expression::FunctionExpression(func) = &prop.value { + if prop.kind.is_accessor() + && matches!(func.r#type, FunctionType::TSEmptyBodyFunctionExpression) + { + ctx.error(accessor_without_body(prop.key.span())); + } + } +} diff --git a/tasks/coverage/parser_typescript.snap b/tasks/coverage/parser_typescript.snap index 67750680b0822..6337e35712b04 100644 --- a/tasks/coverage/parser_typescript.snap +++ b/tasks/coverage/parser_typescript.snap @@ -3,7 +3,7 @@ commit: a709f989 parser_typescript Summary: AST Parsed : 6470/6479 (99.86%) Positive Passed: 6445/6479 (99.48%) -Negative Passed: 1201/5715 (21.01%) +Negative Passed: 1203/5715 (21.05%) Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration10.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration11.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/ClassDeclaration13.ts @@ -31,8 +31,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorAcci Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorDeclarationEmitVisibilityErrors.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorInferredReturnTypeErrorInReturnStatement.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorWithInitializer.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorWithoutBody1.ts -Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorWithoutBody2.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessorsInAmbientContext.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/addMoreOverloadsToBaseSignature.ts @@ -5077,6 +5075,18 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/salsa/typeFro 4 │ } ╰──── + × Getters and setters must have an implementation. + ╭─[typescript/tests/cases/compiler/accessorWithoutBody1.ts:1:15] + 1 │ var v = { get foo() } + · ─── + ╰──── + + × Getters and setters must have an implementation. + ╭─[typescript/tests/cases/compiler/accessorWithoutBody2.ts:1:15] + 1 │ var v = { set foo(a) } + · ─── + ╰──── + × Unexpected token ╭─[typescript/tests/cases/compiler/aliasErrors.ts:13:12] 12 │ import m2 = no.mod;