{"record":{"id":"9b67e0d796414b40","repo":"oxc-project/oxc","slug":"an-interface-declaring-no-members-is-equivalent-to","errorCode":null,"errorMessage":"an interface declaring no members is equivalent to its supertype","messagePattern":"an interface declaring no members is equivalent to its supertype","errorType":"validation","errorClass":"OxcDiagnostic","httpStatus":null,"severity":"warning","filePath":"crates/oxc_linter/src/rules/typescript/no_empty_interface.rs","lineNumber":24,"sourceCode":"use serde::Deserialize;\nuse serde_json::Value;\n\nuse crate::{\n    AstNode,\n    context::{ContextHost, LintContext},\n    rule::{DefaultRuleConfig, Rule},\n};\n\nfn no_empty_interface_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"an empty interface is equivalent to `{}`\")\n        .with_help(\n            \"Add members to this interface, or use a type alias if it is intentionally empty.\",\n        )\n        .with_label(span)\n}\n\nfn no_empty_interface_extend_diagnostic(span: Span) -> OxcDiagnostic {\n    OxcDiagnostic::warn(\"an interface declaring no members is equivalent to its supertype\")\n        .with_help(\"Remove this interface and use the extended type directly or add members to this interface.\")\n        .with_label(span)\n}\n\n#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]\n#[serde(rename_all = \"camelCase\", default, deny_unknown_fields)]\npub struct NoEmptyInterface {\n    /// When set to `true`, allows empty interfaces that extend a single interface.\n    #[serde(alias = \"allow_single_extends\")]\n    // for backwards-compatibility, we made a mistake in the naming previously\n    allow_single_extends: bool,\n}\n\ndeclare_oxc_lint!(\n    /// ### What it does\n    ///\n    /// Disallow the declaration of empty interfaces.\n    ///","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/oxc-project/oxc/blob/e1e7af627c8843ab64044ed466b128fcc21a035b/crates/oxc_linter/src/rules/typescript/no_empty_interface.rs#L6-L42","documentation":"Extend variant of typescript/no-empty-interface: an interface whose body is empty but which has an extends clause. It is reported as equivalent to its supertype — the declaration adds nothing and can be replaced by using the extended type directly. By default allowSingleExtends is false, so even a single-extends empty interface is reported; with allowSingleExtends true, interfaces extending exactly one type are allowed (multiple extends are always reported, since that pattern is the idiomatic union-substitute).","triggerScenarios":"`interface Foo extends Bar {}` with allowSingleExtends unset/false, or `interface Foo extends Bar, Baz {}` regardless of the option; the rule checks interface.extends.len() == 1 && !allow_single_extends for the single case.","commonSituations":"Placeholder interfaces created to be extended later; workarounds copying an external type under a local name; migration code where members were removed; teams that intentionally use single-extends empty interfaces for naming/documentation and need allowSingleExtends: true.","solutions":["Use the extended type directly at the usage sites and delete the empty interface","Add members so the interface actually refines its supertype","If single-extend naming aliases are a deliberate pattern in the codebase, set \"allowSingleExtends\": true in .oxlintrc.json"],"exampleFix":"// before\ninterface Props extends BaseProps {}\n\n// after\n// delete Props and use BaseProps directly:\nfunction Widget(props: BaseProps) { ... }\n// or give it real members:\ninterface Props extends BaseProps {\n  compact: boolean;\n}","handlingStrategy":"validation","validationCode":"// .oxlintrc.json — allow the single-extend naming pattern if the team uses it\n{\n  \"rules\": {\n    \"typescript/no-empty-interface\": [\"warn\", { \"allowSingleExtends\": true }]\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Alias supertypes with `type Foo = Bar` when you only need a new name, not an interface","Use interfaces only when they add or refine members","Set allowSingleExtends deliberately if empty single-extend interfaces are an accepted local idiom"],"tags":["typescript","lint","interface","inheritance","oxlint"],"backgroundTag":"empty-interface","analyzedSha":"e1e7af627c8843ab64044ed466b128fcc21a035b","analyzedAt":"2026-08-20T07:01:07.079Z","contentChangedAt":"2026-08-20T07:01:07.079Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}