diff --git a/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs b/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs index f8da2021b9f29..079b4ff4bb7ec 100644 --- a/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs +++ b/crates/oxc_linter/src/rules/typescript/consistent_type_definitions.rs @@ -99,50 +99,53 @@ impl Rule for ConsistentTypeDefinitions { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { match node.kind() { - AstKind::TSTypeAliasDeclaration(decl) => match &decl.type_annotation { - TSType::TSTypeLiteral(_) - if self.0 == ConsistentTypeDefinitionsConfig::Interface => - { - let start = if decl.declare { - let base_start = decl.span.start + 7; - - ctx.find_next_token_from(base_start, "type") - .map_or(base_start + 1, |v| v + base_start) - } else { - decl.span.start - }; - - let name_span_start = &decl.id.span.start; - let mut name_span_end = &decl.id.span.end; - - if let Some(params) = &decl.type_parameters { - name_span_end = ¶ms.span.end; - } - - let name = - &ctx.source_text()[*name_span_start as usize..*name_span_end as usize]; - - if let TSType::TSTypeLiteral(type_ann) = &decl.type_annotation { - let body_span = type_ann.span; - let body = - &ctx.source_text()[body_span.start as usize..body_span.end as usize]; - - ctx.diagnostic_with_fix( - consistent_type_definitions_diagnostic( - ConsistentTypeDefinitionsConfig::Interface, - Span::new(start, start + 4), - ), - |fixer| { - fixer.replace( - Span::new(start, decl.span.end), - format!("interface {name} {body}"), - ) - }, - ); + AstKind::TSTypeAliasDeclaration(decl) => { + let type_annotation = decl.type_annotation.without_parenthesized(); + match type_annotation { + TSType::TSTypeLiteral(_) + if self.0 == ConsistentTypeDefinitionsConfig::Interface => + { + let start = if decl.declare { + let base_start = decl.span.start + 7; + + ctx.find_next_token_from(base_start, "type") + .map_or(base_start + 1, |v| v + base_start) + } else { + decl.span.start + }; + + let name_span_start = &decl.id.span.start; + let mut name_span_end = &decl.id.span.end; + + if let Some(params) = &decl.type_parameters { + name_span_end = ¶ms.span.end; + } + + let name = + &ctx.source_text()[*name_span_start as usize..*name_span_end as usize]; + + if let TSType::TSTypeLiteral(type_ann) = type_annotation { + let body_span = type_ann.span; + let body = &ctx.source_text() + [body_span.start as usize..body_span.end as usize]; + + ctx.diagnostic_with_fix( + consistent_type_definitions_diagnostic( + ConsistentTypeDefinitionsConfig::Interface, + Span::new(start, start + 4), + ), + |fixer| { + fixer.replace( + Span::new(start, decl.span.end), + format!("interface {name} {body}"), + ) + }, + ); + } } + _ => {} } - _ => {} - }, + } AstKind::ExportDefaultDeclaration(exp) => match &exp.declaration { ExportDefaultDeclarationKind::TSInterfaceDeclaration(decl) @@ -386,6 +389,9 @@ fn test() { ("export declare…interface S {}", Some(serde_json::json!(["type"]))), ("declare /* interface */ interface T { x: number; };", Some(serde_json::json!(["type"]))), ("declare /* type */ type T = { x: number; };", Some(serde_json::json!(["interface"]))), + ("type foo = ({});", Some(serde_json::json!(["interface"]))), + ("type foo = (({}));", Some(serde_json::json!(["interface"]))), + ("type foo = ({ x: number });", Some(serde_json::json!(["interface"]))), ]; let fix = vec![ @@ -544,6 +550,13 @@ export declare type Test = { "export declare…type S = {}", Some(serde_json::json!(["type"])), ), + ("type foo = ({});", "interface foo {}", Some(serde_json::json!(["interface"]))), + ("type foo = (({}));", "interface foo {}", Some(serde_json::json!(["interface"]))), + ( + "type foo = ({ x: number });", + "interface foo { x: number }", + Some(serde_json::json!(["interface"])), + ), ]; let fix_dangerous = vec![ diff --git a/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap b/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap index 9a5553acd651b..8d0a3fbc9dcea 100644 --- a/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap +++ b/crates/oxc_linter/src/snapshots/typescript_consistent_type_definitions.snap @@ -240,3 +240,24 @@ source: crates/oxc_linter/src/tester.rs · ──── ╰──── help: Replace `type T = { x: number; };` with `interface T { x: number; }`. + + ⚠ typescript-eslint(consistent-type-definitions): Use `interface` instead of `type`. + ╭─[consistent_type_definitions.tsx:1:1] + 1 │ type foo = ({}); + · ──── + ╰──── + help: Replace `type foo = ({});` with `interface foo {}`. + + ⚠ typescript-eslint(consistent-type-definitions): Use `interface` instead of `type`. + ╭─[consistent_type_definitions.tsx:1:1] + 1 │ type foo = (({})); + · ──── + ╰──── + help: Replace `type foo = (({}));` with `interface foo {}`. + + ⚠ typescript-eslint(consistent-type-definitions): Use `interface` instead of `type`. + ╭─[consistent_type_definitions.tsx:1:1] + 1 │ type foo = ({ x: number }); + · ──── + ╰──── + help: Replace `type foo = ({ x: number });` with `interface foo { x: number }`.