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 {}”

{}, also known as the “empty object” type, doesn’t actually represent an empty object (despite what many new to TypeScript may assume).
Due to TypeScript’s type system being structural instead of nominal, it actually accepts any non-nullish value, The following example is thus perfectly valid TypeScript:

const n: {} = 0;

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: keyof any]: never } or Record<keyof any, never>: Represent object types whose properties are all of type never (and cannot be used)
  • { [myUniqueInternalSymbol]?: never }: Represents an object type whose only “property” is an unexported unique symbol, thereby forcing external consumers to omit it1.
    This can be used as a type guard for use in extends clauses or a type annotation for use in excess property checks, both with their own respective use cases and pitfalls.

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:

// equivalent to `{}`
type AnythingNotNullish = NonNullable<unknown>;
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-nullish 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 whose properties cannot be used”, use ’{ [k: keyof any]: never }’ or ‘Record<keyof any, never>’ instead.
- If you want a type meaning “an object that cannot contain any properties whatsoever”, use ’{ [uniqueSymbol]?: never }’ with an unexported unique symbol in the same file.

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-nullish 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 whose properties cannot be used”, use ’{ [k: keyof any]: never }’ or ‘Record<keyof any, never>’ instead.
- If you want a type meaning “an object that cannot contain any properties whatsoever”, use ’{ [uniqueSymbol]?: never }’ with an unexported unique symbol in the same file.

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 & {};
  1. In this case, you’d write declare const myUniqueInternalSymbol: unique symbol somewhere in the same file.