src/content/docs/linter/rules/no-banned-types.mdx
import { Tabs, TabItem } from '@astrojs/starlight/components';
<Tabs> <TabItem label="TypeScript and TSX" icon="seti:typescript"> ## Summary - Rule available since: `v1.0.0` - Diagnostic Category: [`lint/complexity/noBannedTypes`](/reference/diagnostics#diagnostic-category) - This rule is **recommended**, meaning it is enabled by default. - This rule has a [**safe**](/linter/#safe-fixes) fix. - The default severity of this rule is [**warning**](/reference/diagnostics#warning). - Sources: - Same as [`@typescript-eslint/ban-types`](https://typescript-eslint.io/rules/ban-types) - Inspired from [`@typescript-eslint/no-empty-object-type`](https://typescript-eslint.io/rules/no-empty-object-type) - Inspired from [`@typescript-eslint/no-wrapper-object-types`](https://typescript-eslint.io/rules/no-wrapper-object-types) - Inspired from [`@typescript-eslint/no-unsafe-function-type`](https://typescript-eslint.io/rules/no-unsafe-function-type){
"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.
Boolean and NumberJavaScript'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.
Function typeTypeScript'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{}{}, 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 valueunknown: 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:
function f<T extends {}>(x: T) {
assert(x != null);
}
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";
const bool = true as Boolean;
let invalidTuple: [string, Number] = ["foo", 12];
function badFunction(cb: Function) {
cb(12);
}
const notEmpty: {} = {prop: 12};
const alsoNotAnObj: Object = "foo";
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 & {};
In this case, you'd write declare const myUniqueInternalSymbol: unique symbol somewhere in the same file. ↩