oxc-project/oxc · warning · OxcDiagnostic
Do not use an empty interface declaration.
Error message
Do not use an empty interface declaration.
What it means
Diagnostic from oxlint's port of typescript-eslint's no-empty-object-type rule. An interface with no members (interface Foo {}) behaves like the {} type and accepts any non-nullish value, so the rule bans it to prevent silent loss of type safety; the help text at crates/oxc_linter/src/rules/typescript/no_empty_object_type.rs:19 states exactly this. It fires when the rule visits an empty TSInterfaceDeclaration that the config (allowInterfaces, allowWithName) does not exempt.
Source
Thrown at crates/oxc_linter/src/rules/typescript/no_empty_object_type.rs:27
use oxc_macros::declare_oxc_lint;
use oxc_semantic::NodeId;
use oxc_span::Span;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{
AstNode,
context::LintContext,
fixer::RuleFixer,
rule::{DefaultRuleConfig, Rule},
utils::deserialize_regex_option,
};
fn no_empty_object_type_diagnostic<S: Into<Cow<'static, str>>>(
span: Span,
message: S,
) -> OxcDiagnostic {
OxcDiagnostic::warn(message)
.with_help("To avoid confusion around the {} type allowing any non-nullish value, this rule bans usage of the {} type.")
.with_label(span)
}
#[derive(Debug, Default, Clone)]
pub struct NoEmptyObjectType(Box<NoEmptyObjectTypeConfig>);
#[expect(clippy::struct_field_names)]
#[derive(Debug, Default, Clone, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", default, deny_unknown_fields)]
pub struct NoEmptyObjectTypeConfig {
/// Whether to allow empty interfaces.
allow_interfaces: AllowInterfaces,
/// Whether to allow empty object type literals.
allow_object_types: AllowObjectTypes,
/// A stringified regular expression to allow interfaces and object type aliases with the configured name.
///
/// This can be useful if your existing code style includes a pattern of declaring empty types with `{}` instead of `object`.View on GitHub (pinned to e1e7af627c)
Solutions
- Add at least one real member to the interface
- Replace it with a type alias that models the intended shape
- If you truly mean 'exactly the empty object', use `type Foo = Record<string, never>`
- Configure allowInterfaces or allowWithName in oxlintrc when the empty interface is intentional
- Suppress once with `// oxlint-disable-next-line typescript/no-empty-object-type`
Example fix
// before
interface User {}
// after
interface User {
id: string;
} Defensive patterns
Strategy: validation
Validate before calling
# .github/workflows/lint.yml
- run: npx oxlint --deny-warnings .
# or configure the exemption up front in oxlintrc.json
{
"rules": {
"typescript/no-empty-object-type": ["error", { "allowWithName": "^(?:I|Props|Params)$" }]
}
} Prevention
- Run oxlint in CI and as a pre-commit hook so empty interfaces never land on main
- Adopt Record<string, never> as the codebase's only spelling of 'intentionally empty object'
- During Flow-to-TS migrations, grep for `interface \w+ {}` before flipping the lint tier
When it happens
Trigger: Writing `interface Foo {}` with an empty body; writing `interface Foo extends Bar {}` that adds no new members; an ambient .d.ts stub whose members were all removed; an interface whose name does not match the allowWithName regex.
Common situations: Placeholder types left over from prototyping, Flow-to-TypeScript migrations where empty interfaces were idiomatic, declaration merging that leaves one empty declaration, enabling the typescript restriction preset in oxlint which turns this rule on.
Related errors
- an empty interface is equivalent to `{}`
- 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"
AI-assisted analysis of oxc-project/oxc@e1e7af627c (2026-08-20).
Data as JSON: /api/errors/1c003dd8f16268e4.
Report an issue: GitHub.