From 2b645e2bba14251a0bf3e848e05cab560438fa69 Mon Sep 17 00:00:00 2001 From: Dunqing <29533304+Dunqing@users.noreply.github.com> Date: Thu, 16 Oct 2025 21:49:57 +0000 Subject: [PATCH] fix(formatter): don't wrap parenthesis for `type` when its grandparent isn't a `ExpressionStatement` (#14654) --- .../src/parentheses/expression.rs | 28 ++++++++++++++++--- .../tests/fixtures/ts/assignments/type.ts | 8 ++++++ .../fixtures/ts/assignments/type.ts.snap | 24 ++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts create mode 100644 crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts.snap diff --git a/crates/oxc_formatter/src/parentheses/expression.rs b/crates/oxc_formatter/src/parentheses/expression.rs index c2719d3d52134..c70014eff2623 100644 --- a/crates/oxc_formatter/src/parentheses/expression.rs +++ b/crates/oxc_formatter/src/parentheses/expression.rs @@ -99,10 +99,7 @@ impl<'a> NeedsParentheses<'a> for AstNode<'a, IdentifierReference<'a>> { } name => { // - matches!( - self.parent, - AstNodes::TSSatisfiesExpression(_) | AstNodes::TSAsExpression(_) - ) && matches!( + if !matches!( name, "await" | "interface" @@ -112,6 +109,29 @@ impl<'a> NeedsParentheses<'a> for AstNode<'a, IdentifierReference<'a>> { | "component" | "hook" | "type" + ) { + return false; + } + + let mut parent = self.parent; + while matches!( + parent, + AstNodes::TSSatisfiesExpression(_) | AstNodes::TSAsExpression(_) + ) { + parent = parent.parent(); + } + + // Early return if the parent isn't a `TSSatisfiesExpression` or `TSAsExpression` + if core::ptr::eq(self.parent, parent) { + return false; + } + + matches!( + parent, AstNodes::ExpressionStatement(stmt) if + !matches!( + stmt.parent.parent(), AstNodes::ArrowFunctionExpression(arrow) + if arrow.expression() + ) ) } } diff --git a/crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts b/crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts new file mode 100644 index 0000000000000..50b0963d7617a --- /dev/null +++ b/crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts @@ -0,0 +1,8 @@ +(type) as unknown; +(type) satisfies unknown; + +() => (type) as unknown; +() => (type) satisfies unknown; + +((type) as any)['t']; +((type) satisfies any)['t']; diff --git a/crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts.snap b/crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts.snap new file mode 100644 index 0000000000000..a05d41f046006 --- /dev/null +++ b/crates/oxc_formatter/tests/fixtures/ts/assignments/type.ts.snap @@ -0,0 +1,24 @@ +--- +source: crates/oxc_formatter/tests/fixtures/mod.rs +--- +==================== Input ==================== +(type) as unknown; +(type) satisfies unknown; + +() => (type) as unknown; +() => (type) satisfies unknown; + +((type) as any)['t']; +((type) satisfies any)['t']; + +==================== Output ==================== +(type) as unknown; +(type) satisfies unknown; + +() => type as unknown; +() => type satisfies unknown; + +(type as any)["t"]; +(type satisfies any)["t"]; + +===================== End =====================