Skip to main content

no-empty-object-type

Disallow accidentally using the "empty object" type.

💡

Some problems reported by this rule are manually fixable by editor suggestions.

The {}, or "empty object" type in TypeScript is a common source of confusion for developers unfamiliar with TypeScript's structural typing. {} represents any non-nullish value, including literals like 0 and "":

let anyNonNullishValue: {} = 'Intentionally allowed by TypeScript.';

Often, developers writing {} actually mean either:

  • object: representing any object value
  • unknown: representing any value at all, including null and undefined

In other words, the "empty object" type {} really means "any value that is defined". That includes arrays, class instances, functions, and primitives such as string and symbol.

To avoid confusion around the {} type allowing any non-nullish value, this rule bans usage of the {} type. That includes interfaces and object type aliases with no fields.

tip

If you do have a use case for an API allowing {}, you can always configure the rule's options, use an ESLint disable comment, or disable the rule in your ESLint config.

Note that this rule does not report on:

  • {} as a type constituent in an intersection type (e.g. types like TypeScript's built-in type NonNullable<T> = T & {}), as this can be useful in type system operations.
  • Interfaces that extend from multiple other interfaces.
eslint.config.mjs
export default tseslint.config({
rules: {
"@typescript-eslint/no-empty-object-type": "error"
}
});

Try this rule in the playground ↗

Examples

let anyObject: {};
let anyValue: {};

interface AnyObjectA {}
interface AnyValueA {}

type AnyObjectB = {};
type AnyValueB = {};
Open in Playground

Options

This rule accepts the following options:

type Options = [
{
/** Whether to allow empty interfaces. */
allowInterfaces?:
| 'never'
| 'with-single-extends'
/** Whether to allow empty interfaces. */
| 'always';
/** Whether to allow empty object type literals. */
allowObjectTypes?:
| 'never'
/** Whether to allow empty object type literals. */
| 'always';
/** A stringified regular expression to allow interfaces and object type aliases with the configured name. */
allowWithName?: string;
},
];

const defaultOptions: Options = [
{ allowInterfaces: 'never', allowObjectTypes: 'never' },
];

By default, this rule flags both interfaces and object types.

allowInterfaces

Whether to allow empty interfaces. Default: "never".

Allowed values are:

  • 'always': to always allow interfaces with no fields
  • 'never' (default): to never allow interfaces with no fields
  • 'with-single-extends': to allow empty interfaces that extend from a single base interface

Examples of correct code for this rule with { allowInterfaces: 'with-single-extends' }:

interface Base {
value: boolean;
}

interface Derived extends Base {}
Open in Playground

allowObjectTypes

Whether to allow empty object type literals. Default: "never".

Allowed values are:

  • 'always': to always allow object type literals with no fields
  • 'never' (default): to never allow object type literals with no fields

allowWithName

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.

Examples of code for this rule with { allowWithName: 'Props$' }:

interface InterfaceValue {}

type TypeValue = {};
Open in Playground

When Not To Use It

If your code commonly needs to represent the "any non-nullish value" type, this rule may not be for you. Projects that extensively use type operations such as conditional types and mapped types oftentimes benefit from disabling this rule.

Further Reading

Resources