oxc-project/oxc · warning · OxcDiagnostic

an interface declaring no members is equivalent to its super

Error message

an interface declaring no members is equivalent to its supertype

What it means

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).

Source

Thrown at crates/oxc_linter/src/rules/typescript/no_empty_interface.rs:24

use serde::Deserialize;
use serde_json::Value;

use crate::{
    AstNode,
    context::{ContextHost, LintContext},
    rule::{DefaultRuleConfig, Rule},
};

fn no_empty_interface_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("an empty interface is equivalent to `{}`")
        .with_help(
            "Add members to this interface, or use a type alias if it is intentionally empty.",
        )
        .with_label(span)
}

fn no_empty_interface_extend_diagnostic(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("an interface declaring no members is equivalent to its supertype")
        .with_help("Remove this interface and use the extended type directly or add members to this interface.")
        .with_label(span)
}

#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoEmptyInterface {
    /// When set to `true`, allows empty interfaces that extend a single interface.
    #[serde(alias = "allow_single_extends")]
    // for backwards-compatibility, we made a mistake in the naming previously
    allow_single_extends: bool,
}

declare_oxc_lint!(
    /// ### What it does
    ///
    /// Disallow the declaration of empty interfaces.
    ///

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Use the extended type directly at the usage sites and delete the empty interface
  2. Add members so the interface actually refines its supertype
  3. If single-extend naming aliases are a deliberate pattern in the codebase, set "allowSingleExtends": true in .oxlintrc.json

Example fix

// before
interface Props extends BaseProps {}

// after
// delete Props and use BaseProps directly:
function Widget(props: BaseProps) { ... }
// or give it real members:
interface Props extends BaseProps {
  compact: boolean;
}
Defensive patterns

Strategy: validation

Validate before calling

// .oxlintrc.json — allow the single-extend naming pattern if the team uses it
{
  "rules": {
    "typescript/no-empty-interface": ["warn", { "allowSingleExtends": true }]
  }
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20). Data as JSON: /api/errors/9b67e0d796414b40. Report an issue: GitHub.