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 previouslyView on GitHub (pinned to e1e7af627c)
Solutions
- Add the intended members to the interface
- If intentionally empty, replace with a type alias: `type Foo = {}` is still weak, so prefer modeling what it actually accepts, or keep it documented
- 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
- Fill in interfaces before committing scaffolding; empty types are flagged because {} accepts almost everything
- For intentionally weak types, write `type Foo = Record<string, never>` or model the real constraint instead
- Let the rule run in CI so placeholder interfaces do not accumulate across branches
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
- encountered allocation error
- Prefer explicitly define the object shape
- Don't use `Function` as a type
- 'The `Object` type actually means "any non-nullish value"
- Do not use any type assertions.
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/c61c6bd14d29c5ff.
Report an issue: GitHub.