oxc-project/oxc · warning · OxcDiagnostic

Prefer explicitly define the object shape

Error message

Prefer explicitly define the object shape

What it means

Warning from typescript/ban-types via type_literal() (crates/oxc_linter/src/rules/typescript/ban_types.rs:23). It fires when '{}' is used as a type: the empty object type actually means 'any non-nullish value' (accepts numbers, strings, functions...), which is broader than 'any object' and hides intent.

Source

Thrown at crates/oxc_linter/src/rules/typescript/ban_types.rs:23

use oxc_span::Span;

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

fn type_diagnostic(banned_type: &str, suggested_type: &str, span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn(format!(
        "Do not use {banned_type:?} as a type. Use \"{suggested_type}\" instead"
    ))
    .with_help(format!("Replace {banned_type:?} with the lowercase primitive type \"{suggested_type}\"."))
    .with_note(format!("{banned_type} is a wrapper object type, while {suggested_type} is the primitive type. Using the primitive type is more idiomatic and avoids confusion between the object wrapper and the primitive value."))
    .with_label(span)
}

fn type_literal(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Prefer explicitly define the object shape")
        .with_help("This type means \"any non-nullish value\", which is slightly better than 'unknown', but it's still a broad type")
        .with_label(span)
}

fn function(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("Don't use `Function` as a type")
        .with_help("The `Function` type accepts any function-like value")
        .with_label(span)
}

fn object(span: Span) -> OxcDiagnostic {
    OxcDiagnostic::warn("'The `Object` type actually means \"any non-nullish value\"")
        .with_help("Replace `Object` with a more specific type. If you need a generic object, use `Record<string, unknown>` or define an interface/type with explicit properties. If you need any value, use `unknown` instead.")
        .with_note("The `Object` type is confusing because it doesn't mean 'any object' - it means 'any non-nullish value', which includes primitives. This makes code harder to understand and can lead to unexpected behavior.")
        .with_label(span)
}

#[derive(Debug, Default, Clone)]

View on GitHub (pinned to e1e7af627c)

Solutions

  1. Use 'Record<string, unknown>' when you mean a string-keyed dictionary
  2. Use 'object' when you mean any non-primitive value
  3. Declare an explicit interface/type with the real members, or use 'unknown' when nothing is known about the value

Example fix

// before
declare function setProps(props: {}): void;

// after
declare function setProps(props: Record<string, unknown>): void;
Defensive patterns

Strategy: validation

Validate before calling

const EMPTY = /:\s*\{\s*\}\s*(;|,|\)|=)/;
if (EMPTY.test(source)) fail('empty object type {} used as a type');

Type guard

function isNonEmptyObjectType(t: unknown): t is Record<string, unknown> {
  return typeof t === 'object' && t !== null && !Array.isArray(t);
}

Prevention

When it happens

Trigger: Annotations like 'let x: {} = getValue()', function parameters typed '{}', or generic constraints using '{}' — any TSObjectTypeLiteral with zero members hit by the rule's visitor.

Common situations: Using {} as a quick 'some object' placeholder during prototyping; TypeScript codebases where '{}' slipped in as a default generic constraint; refactors where an interface was emptied to '{}' instead of deleted.

Related errors


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