1 | # `ban-types`
|
2 |
|
3 | Bans specific types from being used.
|
4 |
|
5 | Some builtin types have aliases, some types are considered dangerous or harmful.
|
6 | It's often a good idea to ban certain types to help with consistency and safety.
|
7 |
|
8 | ## Rule Details
|
9 |
|
10 | This rule bans specific types and can suggest alternatives.
|
11 | Note that it does not ban the corresponding runtime objects from being used.
|
12 |
|
13 | ## Options
|
14 |
|
15 | ```ts
|
16 | type Options = {
|
17 | types?: {
|
18 | [typeName: string]:
|
19 | | false
|
20 | | string
|
21 | | {
|
22 | message: string;
|
23 | fixWith?: string;
|
24 | };
|
25 | };
|
26 | extendDefaults?: boolean;
|
27 | };
|
28 | ```
|
29 |
|
30 | The rule accepts a single object as options.
|
31 |
|
32 | ### `types`
|
33 |
|
34 | An object whose keys are the types you want to ban, and the values are error messages.
|
35 |
|
36 | The type can either be a type name literal (`Foo`), a type name with generic parameter instantiation(s) (`Foo<Bar>`), the empty object literal (`{}`), or the empty tuple type (`[]`).
|
37 |
|
38 | The values can be:
|
39 |
|
40 | - A string, which is the error message to be reported; or
|
41 | - `false` to specifically un-ban this type (useful when you are using `extendDefaults`); or
|
42 | - An object with the following properties:
|
43 | - `message: string` - the message to display when the type is matched.
|
44 | - `fixWith?: string` - a string to replace the banned type with when the fixer is run. If this is omitted, no fix will be done.
|
45 |
|
46 | ### `extendDefaults`
|
47 |
|
48 | If you're specifying custom `types`, you can set this to `true` to extend the default `types` configuration. This is a convenience option to save you copying across the defaults when adding another type.
|
49 |
|
50 | If this is `false`, the rule will _only_ use the types defined in your configuration.
|
51 |
|
52 | Example configuration:
|
53 |
|
54 | ```jsonc
|
55 | {
|
56 | "@typescript-eslint/ban-types": [
|
57 | "error",
|
58 | {
|
59 | "types": {
|
60 | // add a custom message to help explain why not to use it
|
61 | "Foo": "Don't use Foo because it is unsafe",
|
62 |
|
63 | // add a custom message, AND tell the plugin how to fix it
|
64 | "OldAPI": {
|
65 | "message": "Use NewAPI instead",
|
66 | "fixWith": "NewAPI"
|
67 | },
|
68 |
|
69 | // un-ban a type that's banned by default
|
70 | "{}": false
|
71 | },
|
72 | "extendsDefaults": true
|
73 | }
|
74 | ]
|
75 | }
|
76 | ```
|
77 |
|
78 | ### Default Options
|
79 |
|
80 | The default options provide a set of "best practices", intended to provide safety and standardization in your codebase:
|
81 |
|
82 | - Don't use the upper-case primitive types, you should use the lower-case types for consistency.
|
83 | - Avoid the `Function` type, as it provides little safety for the following reasons:
|
84 | - It provides no type safety when calling the value, which means it's easy to provide the wrong arguments.
|
85 | - It accepts class declarations, which will fail when called, as they are called without the `new` keyword.
|
86 | - Avoid the `Object` and `{}` types, as they mean "any non-nullish value".
|
87 | - This is a point of confusion for many developers, who think it means "any object type".
|
88 | - See [this comment for more information](https://github.com/typescript-eslint/typescript-eslint/issues/2063#issuecomment-675156492).
|
89 |
|
90 | :::important
|
91 |
|
92 | The default options suggest using `Record<string, unknown>`; this was a stylistic decision, as the built-in `Record` type is considered to look cleaner.
|
93 |
|
94 | :::
|
95 |
|
96 | <details>
|
97 | <summary>Default Options</summary>
|
98 |
|
99 | ```ts
|
100 | const defaultTypes = {
|
101 | String: {
|
102 | message: 'Use string instead',
|
103 | fixWith: 'string',
|
104 | },
|
105 | Boolean: {
|
106 | message: 'Use boolean instead',
|
107 | fixWith: 'boolean',
|
108 | },
|
109 | Number: {
|
110 | message: 'Use number instead',
|
111 | fixWith: 'number',
|
112 | },
|
113 | Symbol: {
|
114 | message: 'Use symbol instead',
|
115 | fixWith: 'symbol',
|
116 | },
|
117 | BigInt: {
|
118 | message: 'Use bigint instead',
|
119 | fixWith: 'bigint',
|
120 | },
|
121 |
|
122 | Function: {
|
123 | message: [
|
124 | 'The `Function` type accepts any function-like value.',
|
125 | 'It provides no type safety when calling the function, which can be a common source of bugs.',
|
126 | 'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.',
|
127 | 'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.',
|
128 | ].join('\n'),
|
129 | },
|
130 |
|
131 | // object typing
|
132 | Object: {
|
133 | message: [
|
134 | 'The `Object` type actually means "any non-nullish value", so it is marginally better than `unknown`.',
|
135 | '- If you want a type meaning "any object", you probably want `Record<string, unknown>` instead.',
|
136 | '- If you want a type meaning "any value", you probably want `unknown` instead.',
|
137 | ].join('\n'),
|
138 | },
|
139 | '{}': {
|
140 | message: [
|
141 | '`{}` actually means "any non-nullish value".',
|
142 | '- If you want a type meaning "any object", you probably want `Record<string, unknown>` instead.',
|
143 | '- If you want a type meaning "any value", you probably want `unknown` instead.',
|
144 | ].join('\n'),
|
145 | },
|
146 | };
|
147 | ```
|
148 |
|
149 | </details>
|
150 |
|
151 | ### Examples
|
152 |
|
153 | Examples of code with the default options:
|
154 |
|
155 |
|
156 |
|
157 | #### ❌ Incorrect
|
158 |
|
159 | ```ts
|
160 | // use lower-case primitives for consistency
|
161 | const str: String = 'foo';
|
162 | const bool: Boolean = true;
|
163 | const num: Number = 1;
|
164 | const symb: Symbol = Symbol('foo');
|
165 | const bigInt: BigInt = 1n;
|
166 |
|
167 | // use a proper function type
|
168 | const func: Function = () => 1;
|
169 |
|
170 | // use safer object types
|
171 | const capitalObj1: Object = 1;
|
172 | const capitalObj2: Object = { a: 'string' };
|
173 |
|
174 | const curly1: {} = 1;
|
175 | const curly2: {} = { a: 'string' };
|
176 | ```
|
177 |
|
178 | #### ✅ Correct
|
179 |
|
180 | ```ts
|
181 | // use lower-case primitives for consistency
|
182 | const str: string = 'foo';
|
183 | const bool: boolean = true;
|
184 | const num: number = 1;
|
185 | const symb: symbol = Symbol('foo');
|
186 | const bigInt: bigint = 1n;
|
187 |
|
188 | // use a proper function type
|
189 | const func: () => number = () => 1;
|
190 |
|
191 | // use safer object types
|
192 | const lowerObj: object = {};
|
193 |
|
194 | const capitalObj1: number = 1;
|
195 | const capitalObj2: { a: string } = { a: 'string' };
|
196 |
|
197 | const curly1: number = 1;
|
198 | const curly2: Record<'a', string> = { a: 'string' };
|
199 | ```
|
200 |
|
201 | ## Related To
|
202 |
|
203 | - TSLint: [ban-types](https://palantir.github.io/tslint/rules/ban-types)
|
204 |
|
205 | ## Attributes
|
206 |
|
207 | - Configs:
|
208 | - [x] ✅ Recommended
|
209 | - [x] 🔒 Strict
|
210 | - [x] 🔧 Fixable
|
211 | - [ ] 💭 Requires type information
|