diff --git a/changelog_unreleased/typescript/14584.md b/changelog_unreleased/typescript/14584.md new file mode 100644 index 000000000000..70cf954691dd --- /dev/null +++ b/changelog_unreleased/typescript/14584.md @@ -0,0 +1,31 @@ +#### Allow multiple decorators on same getter/setter (#14584 by @fisker) + + +```ts +// Input +class A { + @decorator() + get foo () {} + + @decorator() + set foo (value) {} +} + +// Prettier stable +SyntaxError: Decorators cannot be applied to multiple get/set accessors of the same name. (5:3) + 3 | get foo () {} + 4 | +> 5 | @decorator() + | ^^^^^^^^^^^^ + 6 | set foo (value) {} + 7 | } + +// Prettier main +class A { + @decorator() + get foo() {} + + @decorator() + set foo(value) {} +} +``` diff --git a/src/language-js/parse/postprocess/typescript.js b/src/language-js/parse/postprocess/typescript.js index 926f60432b8e..761cd76d5e06 100644 --- a/src/language-js/parse/postprocess/typescript.js +++ b/src/language-js/parse/postprocess/typescript.js @@ -57,40 +57,19 @@ function throwErrorForInvalidDecorator(node) { const { SyntaxKind } = ts; for (const modifier of modifiers) { - if (ts.isDecorator(modifier)) { - if (!nodeCanBeDecorated(node)) { - if ( - node.kind === SyntaxKind.MethodDeclaration && - // @ts-expect-error -- internal? - !ts.nodeIsPresent(node.body) - ) { - throwErrorOnTsNode( - modifier, - "A decorator can only decorate a method implementation, not an overload." - ); - } else { - throwErrorOnTsNode(modifier, "Decorators are not valid here."); - } - } else if ( - node.kind === SyntaxKind.GetAccessor || - node.kind === SyntaxKind.SetAccessor - ) { + if (ts.isDecorator(modifier) && !nodeCanBeDecorated(node)) { + if ( + node.kind === SyntaxKind.MethodDeclaration && // @ts-expect-error -- internal? - const accessors = ts.getAllAccessorDeclarations( - node.parent.members, - node + !ts.nodeIsPresent(node.body) + ) { + throwErrorOnTsNode( + modifier, + "A decorator can only decorate a method implementation, not an overload." ); - if ( - // @ts-expect-error -- internal? - ts.hasDecorators(accessors.firstAccessor) && - node === accessors.secondAccessor - ) { - throwErrorOnTsNode( - modifier, - "Decorators cannot be applied to multiple get/set accessors of the same name." - ); - } } + + throwErrorOnTsNode(modifier, "Decorators are not valid here."); } } } diff --git a/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap b/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap index 501c86771b3b..d501273a7b5b 100644 --- a/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/format/typescript/decorators/__snapshots__/jsfmt.spec.js.snap @@ -30,7 +30,7 @@ exports[`abstract-method.ts [typescript] format 1`] = ` 5 |" `; -exports[`accessor.ts [babel-ts] format 1`] = ` +exports[`accessor.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] printWidth: 80 @@ -56,17 +56,6 @@ class A { ================================================================================ `; -exports[`accessor.ts [typescript] format 1`] = ` -"Decorators cannot be applied to multiple get/set accessors of the same name. (4:5) - 2 | @foo() - 3 | get a() {return 1} -> 4 | @bar() - | ^^^^^^ - 5 | set a(v) {} - 6 | } - 7 |" -`; - exports[`argument-list-preserve-line.ts format 1`] = ` ====================================options===================================== parsers: ["typescript"] diff --git a/tests/format/typescript/decorators/jsfmt.spec.js b/tests/format/typescript/decorators/jsfmt.spec.js index 3e59a6c31678..78dd2704f5ec 100644 --- a/tests/format/typescript/decorators/jsfmt.spec.js +++ b/tests/format/typescript/decorators/jsfmt.spec.js @@ -1,3 +1,3 @@ run_spec(__dirname, ["typescript"], { - errors: { typescript: ["abstract-method.ts", "accessor.ts"] }, + errors: { typescript: ["abstract-method.ts"] }, });