0
# Builtin Type Checks
1
2
Specialized predicates for identifying built-in TypeScript types like Promise, Error, and readonly utility types. These functions help recognize common patterns and built-in type constructs in TypeScript code.
3
4
## Capabilities
5
6
### Promise Type Checks
7
8
Functions for identifying Promise-related types and patterns.
9
10
```typescript { .api }
11
/**
12
* Checks if a type is Promise-like (extends Promise)
13
* Example: class DerivedClass extends Promise<number> {} - DerivedClass is Promise-like
14
*/
15
function isPromiseLike(program: ts.Program, type: ts.Type): boolean;
16
17
/**
18
* Checks if a type is PromiseConstructor-like
19
* Example: const value = Promise; value.reject - value is PromiseConstructor-like
20
*/
21
function isPromiseConstructorLike(program: ts.Program, type: ts.Type): boolean;
22
```
23
24
**Usage Examples:**
25
26
```typescript
27
import { isPromiseLike, isPromiseConstructorLike } from "@typescript-eslint/type-utils";
28
29
// In an ESLint rule checking async patterns
30
export default {
31
create(context) {
32
const services = context.parserServices;
33
const program = services.program;
34
const checker = program.getTypeChecker();
35
36
return {
37
VariableDeclarator(node) {
38
if (node.init) {
39
const tsNode = services.esTreeNodeToTSNodeMap.get(node.init);
40
const type = checker.getTypeAtLocation(tsNode);
41
42
if (isPromiseLike(program, type)) {
43
// Handle Promise-like types
44
context.report({
45
node,
46
messageId: "promiseDetected",
47
data: { typeName: checker.typeToString(type) }
48
});
49
}
50
51
if (isPromiseConstructorLike(program, type)) {
52
// Handle Promise constructor references
53
context.report({
54
node,
55
messageId: "promiseConstructorUsage"
56
});
57
}
58
}
59
}
60
};
61
}
62
};
63
```
64
65
### Error Type Checks
66
67
Functions for identifying Error-related types and inheritance patterns.
68
69
```typescript { .api }
70
/**
71
* Checks if a type extends the Error class
72
* Example: class Foo extends Error {} - new Foo() is Error-like
73
*/
74
function isErrorLike(program: ts.Program, type: ts.Type): boolean;
75
76
/**
77
* Checks if a type is a readonly Error type (like Readonly<Error>)
78
*/
79
function isReadonlyErrorLike(program: ts.Program, type: ts.Type): boolean;
80
```
81
82
**Usage Examples:**
83
84
```typescript
85
import { isErrorLike, isReadonlyErrorLike } from "@typescript-eslint/type-utils";
86
87
// In an ESLint rule for error handling
88
export default {
89
create(context) {
90
const services = context.parserServices;
91
const program = services.program;
92
const checker = program.getTypeChecker();
93
94
return {
95
ThrowStatement(node) {
96
const tsNode = services.esTreeNodeToTSNodeMap.get(node.argument);
97
const type = checker.getTypeAtLocation(tsNode);
98
99
if (!isErrorLike(program, type)) {
100
context.report({
101
node: node.argument,
102
messageId: "throwNonError"
103
});
104
}
105
},
106
107
CatchClause(node) {
108
if (node.param) {
109
const tsNode = services.esTreeNodeToTSNodeMap.get(node.param);
110
const type = checker.getTypeAtLocation(tsNode);
111
112
if (isReadonlyErrorLike(program, type)) {
113
context.report({
114
node: node.param,
115
messageId: "readonlyErrorInCatch"
116
});
117
}
118
}
119
}
120
};
121
}
122
};
123
```
124
125
### Readonly Utility Type Checks
126
127
Functions for identifying TypeScript's built-in readonly utility types.
128
129
```typescript { .api }
130
/**
131
* Checks if a type is a Readonly type alias
132
* Example: type T = Readonly<{ foo: 'bar' }> - T is ReadonlyTypeLike
133
*/
134
function isReadonlyTypeLike(
135
program: ts.Program,
136
type: ts.Type,
137
predicate?: (subType: { aliasSymbol: ts.Symbol; aliasTypeArguments: readonly ts.Type[] } & ts.Type) => boolean
138
): boolean;
139
```
140
141
**Usage Examples:**
142
143
```typescript
144
import { isReadonlyTypeLike } from "@typescript-eslint/type-utils";
145
146
// Check for Readonly utility type usage
147
export default {
148
create(context) {
149
const services = context.parserServices;
150
const program = services.program;
151
const checker = program.getTypeChecker();
152
153
return {
154
TSTypeReference(node) {
155
const tsNode = services.esTreeNodeToTSNodeMap.get(node);
156
const type = checker.getTypeAtLocation(tsNode);
157
158
if (isReadonlyTypeLike(program, type)) {
159
// Found Readonly<T> usage
160
context.report({
161
node,
162
messageId: "readonlyUtilityType"
163
});
164
}
165
}
166
};
167
}
168
};
169
```
170
171
### Generic Builtin Type Checking
172
173
Generic functions for building custom builtin type checkers.
174
175
```typescript { .api }
176
/**
177
* Generic function to check if a type matches a built-in type alias with a predicate
178
*/
179
function isBuiltinTypeAliasLike(
180
program: ts.Program,
181
type: ts.Type,
182
predicate: (subType: {aliasSymbol: ts.Symbol; aliasTypeArguments: readonly ts.Type[]} & ts.Type) => boolean
183
): boolean;
184
185
/**
186
* Checks if a type is like a built-in symbol with the given name(s)
187
*/
188
function isBuiltinSymbolLike(
189
program: ts.Program,
190
type: ts.Type,
191
symbolName: string | string[]
192
): boolean;
193
194
/**
195
* Recursive helper function for built-in symbol-like checks.
196
* Handles inheritance, unions, intersections, and type parameters.
197
*/
198
function isBuiltinSymbolLikeRecurser(
199
program: ts.Program,
200
type: ts.Type,
201
predicate: (subType: ts.Type) => boolean | null
202
): boolean;
203
```
204
205
**Usage Examples:**
206
207
```typescript
208
import {
209
isBuiltinTypeAliasLike,
210
isBuiltinSymbolLike,
211
isBuiltinSymbolLikeRecurser
212
} from "@typescript-eslint/type-utils";
213
214
// Custom builtin type checker for Record<K, V>
215
function isRecordLike(program: ts.Program, type: ts.Type): boolean {
216
return isBuiltinTypeAliasLike(program, type, (subType) => {
217
return subType.aliasSymbol?.name === 'Record' &&
218
subType.aliasTypeArguments?.length === 2;
219
});
220
}
221
222
// Check for Map or Set types
223
function isMapOrSetLike(program: ts.Program, type: ts.Type): boolean {
224
return isBuiltinSymbolLike(program, type, ['Map', 'Set']);
225
}
226
227
// Custom predicate-based checker
228
function isIterableLike(program: ts.Program, type: ts.Type): boolean {
229
return isBuiltinSymbolLikeRecurser(program, type, (subType) => {
230
// Check if type has Symbol.iterator method
231
const checker = program.getTypeChecker();
232
const iteratorSymbol = checker.getPropertyOfType(subType, '__@iterator');
233
return iteratorSymbol ? true : null;
234
});
235
}
236
237
// Usage in ESLint rule
238
export default {
239
create(context) {
240
const services = context.parserServices;
241
const program = services.program;
242
const checker = program.getTypeChecker();
243
244
return {
245
VariableDeclarator(node) {
246
if (node.init) {
247
const tsNode = services.esTreeNodeToTSNodeMap.get(node.init);
248
const type = checker.getTypeAtLocation(tsNode);
249
250
if (isRecordLike(program, type)) {
251
// Handle Record types
252
}
253
254
if (isMapOrSetLike(program, type)) {
255
// Handle Map/Set types
256
}
257
258
if (isIterableLike(program, type)) {
259
// Handle iterable types
260
}
261
}
262
}
263
};
264
}
265
};
266
```
267
268
## Advanced Builtin Type Patterns
269
270
### Custom Type Family Checkers
271
272
```typescript
273
// Example: Creating a checker for all array-like builtin types
274
import { isBuiltinSymbolLikeRecurser } from "@typescript-eslint/type-utils";
275
276
function isArrayLikeBuiltin(program: ts.Program, type: ts.Type): boolean {
277
return isBuiltinSymbolLikeRecurser(program, type, (subType) => {
278
const checker = program.getTypeChecker();
279
const symbol = subType.symbol || subType.aliasSymbol;
280
281
if (!symbol) return null;
282
283
const arrayLikeNames = [
284
'Array', 'ReadonlyArray', 'Int8Array', 'Uint8Array',
285
'Int16Array', 'Uint16Array', 'Int32Array', 'Uint32Array',
286
'Float32Array', 'Float64Array', 'ArrayBuffer'
287
];
288
289
return arrayLikeNames.includes(symbol.name) ? true : null;
290
});
291
}
292
```
293
294
### Promise Pattern Detection
295
296
```typescript
297
// Example: Comprehensive Promise pattern analysis
298
import { isPromiseLike, isPromiseConstructorLike } from "@typescript-eslint/type-utils";
299
300
function analyzePromisePatterns(
301
program: ts.Program,
302
type: ts.Type,
303
checker: ts.TypeChecker
304
): {
305
isPromise: boolean;
306
isConstructor: boolean;
307
isThenable: boolean;
308
} {
309
const isPromise = isPromiseLike(program, type);
310
const isConstructor = isPromiseConstructorLike(program, type);
311
312
// Check for thenable (has .then method)
313
const thenProperty = checker.getPropertyOfType(type, 'then');
314
const isThenable = !!thenProperty;
315
316
return { isPromise, isConstructor, isThenable };
317
}
318
```
319
320
### Error Hierarchy Analysis
321
322
```typescript
323
// Example: Analyzing error type hierarchies
324
import { isErrorLike, isReadonlyErrorLike } from "@typescript-eslint/type-utils";
325
326
function analyzeErrorHierarchy(
327
program: ts.Program,
328
type: ts.Type,
329
checker: ts.TypeChecker
330
): {
331
isError: boolean;
332
isReadonlyError: boolean;
333
errorName: string | null;
334
customError: boolean;
335
} {
336
const isError = isErrorLike(program, type);
337
const isReadonlyError = isReadonlyErrorLike(program, type);
338
339
let errorName: string | null = null;
340
let customError = false;
341
342
if (isError) {
343
const symbol = type.symbol || type.aliasSymbol;
344
errorName = symbol?.name || null;
345
346
// Check if it's a custom error (not built-in Error)
347
customError = errorName !== 'Error' && errorName !== null;
348
}
349
350
return { isError, isReadonlyError, errorName, customError };
351
}
352
```