oxc-project/oxc · warning · OxcDiagnostic

an empty interface is equivalent to `{}`

Error message

an empty interface is equivalent to `{}`

What it means

typescript/no-empty-interface reports `interface Foo {}` — an interface with no body members. An empty interface is structurally equivalent to `{}`, which in TypeScript means "any non-nullish value", so it provides no contract. The help suggests adding members or using a type alias if the emptiness is intentional. Note allowSingleExtends does not exempt this variant; it only applies to interfaces that extend exactly one type.

Source

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

use oxc_ast::AstKind;
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use schemars::JsonSchema;
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

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Add the intended members to the interface
  2. If intentionally empty, replace with a type alias: `type Foo = {}` is still weak, so prefer modeling what it actually accepts, or keep it documented
  3. If it exists only to be augmented later, disable the rule for that line or wait to add members before committing

Example fix

// before
interface UserPrefs {}

// after
interface UserPrefs {
  theme: 'light' | 'dark';
  locale: string;
}
Defensive patterns

Strategy: validation

Validate before calling

// .oxlintrc.json
{
  "rules": { "typescript/no-empty-interface": "warn" }
}

Prevention

When it happens

Trigger: Any TSInterfaceDeclaration with an empty body and no extends clause; declared as a placeholder, an accidental empty block, or a leftover after members were moved elsewhere.

Common situations: Scaffolding files where the interface was created but never filled in; merging declarations where ambient augmentation was expected; teams migrating from `no-empty-object-type` conventions; placeholders committed during WIP.

Related errors


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