Skip to content

noBannedTypes

biome.json
{
"linter": {
"rules": {
"complexity": {
"noBannedTypes": "error"
}
}
}
}

Disallow primitive type aliases and misleading types.

This rule aims to prevent usage of potentially “misleading” types and type aliases which may behave unexpectedly.

Disallow “boxed object” types like Boolean and Number

Section titled “Disallow “boxed object” types like Boolean and Number”

JavaScript’s 8 data types are described in TypeScript by the lowercase types undefined, null, boolean, number, string, bigint, symbol, and object.

The latter 6 also have uppercase variants, which instead represent interfaces with the shared properties of their primitive counterparts. Due to the nature of structural typing, these uppercase types accept both primitive values and non-primitive “boxed object”s like new Boolean(true), despite the two behaving differently in many circumstances like equality and truthiness.

It is thus considered best practice to avoid these “boxed types” in favor of their lowercase primitive counterparts.

TypeScript’s built-in Function type is capable of accepting callbacks of any shape or form, behaving equivalent to (...rest: any[]) => any (which uses the unsafe any type) when called directly. It also accepts classes or plain objects that happen to possess all properties of the Function class, which is likewise a potential source of confusion.

As such, it is almost always preferable to explicitly specify function parameters and return types where possible.
When a generic “catch-all” callback type is required, one of the following can be used instead:

  • () => void: A function that accepts no parameters and whose return value is ignored
  • (...args: never) => unknown: A “top type” for functions that can be assigned any function type, but can’t be called directly

Disallow the misleading empty object type {}

Section titled “Disallow the misleading empty object type {}”

In TypeScript, the type {} doesn’t represent an empty object (as many new to the language may assume). It actually accepts any non-nullish value, including non-object primitives. The following TypeScript example is thus perfectly valid:

const n: {} = 0;
code-block.ts:1:10 lint/complexity/noBannedTypes ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ’{}’ as a type.

> 1 │ const n: {} = 0;
^^
2 │

{}’ accepts any non-nullable value, including non-object primitives like ‘123’ and ‘true’.
- If you want a type meaning “any arbitrary object”, use ‘object’ instead.
- If you want a type meaning “any value”, use ‘unknown’ instead.
- If you want a type meaning “an object without any properties”, use ’{ [k: string]: never }’ or ‘Record<string, never>’ instead.

If that’s really what you want, use an inline disable comment.

Often, developers writing {} actually mean one of the following:

  • object: Represents any object value
  • unknown: Represents any value at all, including null and undefined
  • { [k: string]: never } or Record<string, never>: Represent object types that disallow property access

To avoid confusion, this rule forbids the use of the type {}, except in two situations:

  1. In type constraints to restrict a generic type to non-nullable types:
function f<T extends {}>(x: T) {
assert(x != null);
}
  1. In a type intersection to narrow a type to its non-nullable equivalent type:
type NonNullableMyType = MyType & {};

In this last case, you can also use the NonNullable utility type to the same effect:

type NonNullableMyType = NonNullable<MyType>;
let foo: String = "bar";
code-block.ts:1:10 lint/complexity/noBannedTypes  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ‘String’ as a type.

> 1 │ let foo: String = “bar”;
^^^^^^
2 │

Prefer using lowercase primitive types instead of uppercase “boxed object” types.
String’ accepts anything that implements the corresponding interface - both primitives and “primitive-like” objects.
It is considered best practice to use ‘string’ instead in nearly all circumstances.

If that’s really what you want, use an inline disable comment.

Safe fix: Use ‘string’ instead.

1 - let·foo:·String·=·bar;
1+ let·foo:·string·=·bar;
2 2

const bool = true as Boolean;
code-block.ts:1:22 lint/complexity/noBannedTypes  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ‘Boolean’ as a type.

> 1 │ const bool = true as Boolean;
^^^^^^^
2 │

Prefer using lowercase primitive types instead of uppercase “boxed object” types.
Boolean’ accepts anything that implements the corresponding interface - both primitives and “primitive-like” objects.
It is considered best practice to use ‘boolean’ instead in nearly all circumstances.

If that’s really what you want, use an inline disable comment.

Safe fix: Use ‘boolean’ instead.

1 - const·bool·=·true·as·Boolean;
1+ const·bool·=·true·as·boolean;
2 2

let invalidTuple: [string, Number] = ["foo", 12];
code-block.ts:1:28 lint/complexity/noBannedTypes  FIXABLE  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ‘Number’ as a type.

> 1 │ let invalidTuple: [string, Number] = [“foo”, 12];
^^^^^^
2 │

Prefer using lowercase primitive types instead of uppercase “boxed object” types.
Number’ accepts anything that implements the corresponding interface - both primitives and “primitive-like” objects.
It is considered best practice to use ‘number’ instead in nearly all circumstances.

If that’s really what you want, use an inline disable comment.

Safe fix: Use ‘number’ instead.

1 - let·invalidTuple:·[string,·Number]·=·[foo,·12];
1+ let·invalidTuple:·[string,·number]·=·[foo,·12];
2 2

function badFunction(cb: Function) {
cb(12);
}
code-block.ts:1:26 lint/complexity/noBannedTypes ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ‘Function’ as a type.

> 1 │ function badFunction(cb: Function) {
^^^^^^^^
2 │ cb(12);
3 │ }

The ‘Function’ type is unsafe and accepts any arbitrary function or “function-like” value.
Explicitly defining the function’s shape helps prevent mismatching argument types and return values.
If a generic “catch-all” callback type is required, consider using a “top type” like ’(…args: never) => unknown’ instead.

If that’s really what you want, use an inline disable comment.

const notEmpty: {} = {prop: 12};
code-block.ts:1:17 lint/complexity/noBannedTypes ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ’{}’ as a type.

> 1 │ const notEmpty: {} = {prop: 12};
^^
2 │

{}’ accepts any non-nullable value, including non-object primitives like ‘123’ and ‘true’.
- If you want a type meaning “any arbitrary object”, use ‘object’ instead.
- If you want a type meaning “any value”, use ‘unknown’ instead.
- If you want a type meaning “an object without any properties”, use ’{ [k: string]: never }’ or ‘Record<string, never>’ instead.

If that’s really what you want, use an inline disable comment.

const alsoNotAnObj: Object = "foo";
code-block.ts:1:21 lint/complexity/noBannedTypes ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Don’t use ‘Object’ as a type.

> 1 │ const alsoNotAnObj: Object = “foo”;
^^^^^^
2 │

Object’ accepts any non-nullable value, including non-object primitives like ‘123’ and ‘true’.
- If you want a type meaning “any arbitrary object”, use ‘object’ instead.
- If you want a type meaning “any value”, use ‘unknown’ instead.
- If you want a type meaning “an object without any properties”, use ’{ [k: string]: never }’ or ‘Record<string, never>’ instead.

If that’s really what you want, use an inline disable comment.

const foo: string = "bar";
let tuple: [boolean, string] = [false, "foo"];
function betterFunction(cb: (n: number) => string) {
return cb(12);
}
type wrapFn<T extends (...args: never) => unknown> = { func: T }
const goodObj: object = {foo: 12};
type emptyObj = Record<string, never>;

Exceptions for {}:

declare function foo<T extends {}>(x: T): void;
type notNull<T> = T & {};