From 6a307d1d9bd95a051bac84e877fdc21733102445 Mon Sep 17 00:00:00 2001 From: camc314 <18101008+camc314@users.noreply.github.com> Date: Mon, 16 Mar 2026 21:17:07 +0000 Subject: [PATCH] fix(linter/explicit-module-boundary-types): fix false positives for satisfies-wrapped members (#20439) --- .../explicit_module_boundary_types.rs | 56 +++++++++++++++++-- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/crates/oxc_linter/src/rules/typescript/explicit_module_boundary_types.rs b/crates/oxc_linter/src/rules/typescript/explicit_module_boundary_types.rs index 7c48d2718c552..e37635b718ea5 100644 --- a/crates/oxc_linter/src/rules/typescript/explicit_module_boundary_types.rs +++ b/crates/oxc_linter/src/rules/typescript/explicit_module_boundary_types.rs @@ -704,6 +704,27 @@ impl<'a> Visit<'a> for ExplicitTypesChecker<'a, '_> { self.ctx.diagnostic(func_missing_argument_type(it.span)); } + + fn visit_ts_as_expression(&mut self, it: &TSAsExpression<'a>) { + if is_wrapped_function_expression(&it.expression) { + return; + } + walk::walk_ts_as_expression(self, it); + } + + fn visit_ts_satisfies_expression(&mut self, it: &TSSatisfiesExpression<'a>) { + if is_wrapped_function_expression(&it.expression) { + return; + } + walk::walk_ts_satisfies_expression(self, it); + } + + fn visit_ts_type_assertion(&mut self, it: &TSTypeAssertion<'a>) { + if is_wrapped_function_expression(&it.expression) { + return; + } + walk::walk_ts_type_assertion(self, it); + } } /// like [`Expression::get_inner_expression`], but does not skip over most ts syntax @@ -715,6 +736,13 @@ fn get_typed_inner_expression<'a, 'e>(expr: &'e Expression<'a>) -> &'e Expressio } } +fn is_wrapped_function_expression(expr: &Expression<'_>) -> bool { + matches!( + get_typed_inner_expression(expr), + Expression::ArrowFunctionExpression(_) | Expression::FunctionExpression(_) + ) +} + #[cfg(test)] mod test { use super::{ExplicitModuleBoundaryTypes, ExplicitModuleBoundaryTypesConfig}; @@ -924,10 +952,6 @@ mod test { "const x = (() => {}) as Foo;", Some(json!([{ "allowTypedFunctionExpressions": true }])), ), - ( - "type F = (x: number) => number; export const f = (x => x) satisfies F;", - None, - ), ( " export const x = { @@ -1562,6 +1586,30 @@ mod test { ", None, ), + ( + "type F = (x: number) => number; export const f = (x => x) satisfies F;", + None, + ), + ( + " + type F = () => number; + + export const OBJ = { + f: (() => 42) satisfies F, + }; + ", + None, + ), + ( + " + type F = () => number; + + export class Class { + g = (() => 42) satisfies F; + } + ", + None, + ), ]; let fail = vec![