0
# Type System Utilities
1
2
Advanced type system analysis including type assignability checking, property analysis, class type inspection, type manipulation utilities, and comprehensive type system operations for deep TypeScript compiler integration.
3
4
## Capabilities
5
6
### Type Assignability Analysis
7
8
Utilities for checking type compatibility and assignability relationships.
9
10
```typescript { .api }
11
/**
12
* Check if type is assignable to number
13
* @param checker - Type checker instance
14
* @param type - Type to check
15
* @returns true if type is assignable to number
16
*/
17
function isTypeAssignableToNumber(checker: ts.TypeChecker, type: ts.Type): boolean;
18
19
/**
20
* Check if type is assignable to string
21
* @param checker - Type checker instance
22
* @param type - Type to check
23
* @returns true if type is assignable to string
24
*/
25
function isTypeAssignableToString(checker: ts.TypeChecker, type: ts.Type): boolean;
26
27
/**
28
* Check if type is thenable (has then method)
29
* @param checker - Type checker instance
30
* @param node - Node for context
31
* @param type - Type to check
32
* @returns true if type is thenable (Promise-like)
33
*/
34
function isThenableType(checker: ts.TypeChecker, node: ts.Node, type: ts.Type): boolean;
35
36
/**
37
* Check if type is thenable based on expression
38
* @param checker - Type checker instance
39
* @param node - Expression node
40
* @param type - Optional type (inferred from node if not provided)
41
* @returns true if type is thenable
42
*/
43
function isThenableType(checker: ts.TypeChecker, node: ts.Expression, type?: ts.Type): boolean;
44
```
45
46
### Type Classification
47
48
Utilities for classifying and analyzing type characteristics.
49
50
```typescript { .api }
51
/**
52
* Check if type is falsy (null, undefined, false, 0, "", etc.)
53
* @param type - Type to check
54
* @returns true if type is always falsy
55
*/
56
function isFalsyType(type: ts.Type): boolean;
57
58
/**
59
* Check if type is specific boolean literal type
60
* @param type - Type to check
61
* @param literal - Boolean value to match
62
* @returns true if type is the specified boolean literal
63
*/
64
function isBooleanLiteralType(type: ts.Type, literal: boolean): boolean;
65
66
/**
67
* Check if object type is empty (no properties)
68
* @param type - Type to check
69
* @returns true if type is empty object type
70
*/
71
function isEmptyObjectType(type: ts.Type): type is ts.ObjectType;
72
```
73
74
### Optional Chaining and Optionality
75
76
Utilities for handling optional chaining and optional types.
77
78
```typescript { .api }
79
/**
80
* Remove optionality from type (T | undefined -> T)
81
* @param checker - Type checker instance
82
* @param type - Type to process
83
* @returns Type with optionality removed
84
*/
85
function removeOptionalityFromType(checker: ts.TypeChecker, type: ts.Type): ts.Type;
86
87
/**
88
* Remove optional chaining undefined marker type
89
* @param checker - Type checker instance
90
* @param type - Type to process
91
* @returns Type with optional chaining marker removed
92
*/
93
function removeOptionalChainingUndefinedMarkerType(checker: ts.TypeChecker, type: ts.Type): ts.Type;
94
95
/**
96
* Check if type is optional chaining undefined marker
97
* @param checker - Type checker instance
98
* @param type - Type to check
99
* @returns true if type is optional chaining marker
100
*/
101
function isOptionalChainingUndefinedMarkerType(checker: ts.TypeChecker, type: ts.Type): boolean;
102
```
103
104
### Union and Intersection Type Analysis
105
106
Utilities for working with composite types.
107
108
```typescript { .api }
109
/**
110
* Get constituent types of a union type
111
* @param type - Union type to decompose
112
* @returns Array of union member types
113
*/
114
function unionTypeParts(type: ts.Type): ts.Type[];
115
116
/**
117
* Get constituent types of an intersection type
118
* @param type - Intersection type to decompose
119
* @returns Array of intersection member types
120
*/
121
function intersectionTypeParts(type: ts.Type): ts.Type[];
122
123
/**
124
* Test some parts of a union or intersection type
125
* @param type - Type to test
126
* @param predicate - Type predicate function
127
* @param cb - Callback to test each part
128
* @returns true if callback returns true for any part
129
*/
130
function someTypePart(
131
type: ts.Type,
132
predicate: (t: ts.Type) => t is ts.UnionOrIntersectionType,
133
cb: (t: ts.Type) => boolean
134
): boolean;
135
```
136
137
### Property Analysis
138
139
Utilities for analyzing type properties and symbols.
140
141
```typescript { .api }
142
/**
143
* Get property symbol from type by name
144
* @param type - Type to search
145
* @param name - Property name to find
146
* @returns Property symbol if found
147
*/
148
function getPropertyOfType(type: ts.Type, name: ts.__String): ts.Symbol | undefined;
149
150
/**
151
* Get well-known symbol property from type
152
* @param type - Type to search
153
* @param wellKnownSymbolName - Well-known symbol name (e.g., 'iterator')
154
* @param checker - Type checker instance
155
* @returns Property symbol if found
156
*/
157
function getWellKnownSymbolPropertyOfType(
158
type: ts.Type,
159
wellKnownSymbolName: string,
160
checker: ts.TypeChecker
161
): ts.Symbol | undefined;
162
163
/**
164
* Check if property is readonly in type
165
* @param type - Type containing property
166
* @param name - Property name
167
* @param checker - Type checker instance
168
* @returns true if property is readonly
169
*/
170
function isPropertyReadonlyInType(
171
type: ts.Type,
172
name: ts.__String,
173
checker: ts.TypeChecker
174
): boolean;
175
176
/**
177
* Check if symbol has readonly declaration
178
* @param symbol - Symbol to check
179
* @param checker - Type checker instance
180
* @returns true if symbol is declared readonly
181
*/
182
function symbolHasReadonlyDeclaration(symbol: ts.Symbol, checker: ts.TypeChecker): boolean;
183
184
/**
185
* Get property name from type (for computed properties)
186
* @param type - Type representing property name
187
* @returns Property name information if extractable
188
*/
189
function getPropertyNameFromType(type: ts.Type): PropertyName | undefined;
190
191
/**
192
* Property name information interface
193
*/
194
interface PropertyName {
195
displayName: string;
196
symbolName: ts.__String;
197
}
198
```
199
200
### Class Type Analysis
201
202
Specialized utilities for analyzing class types and inheritance.
203
204
```typescript { .api }
205
/**
206
* Get symbol of class-like declaration
207
* @param node - Class-like declaration
208
* @param checker - Type checker instance
209
* @returns Class symbol
210
*/
211
function getSymbolOfClassLikeDeclaration(
212
node: ts.ClassLikeDeclaration,
213
checker: ts.TypeChecker
214
): ts.Symbol;
215
216
/**
217
* Get constructor type of class-like declaration
218
* @param node - Class-like declaration
219
* @param checker - Type checker instance
220
* @returns Constructor type
221
*/
222
function getConstructorTypeOfClassLikeDeclaration(
223
node: ts.ClassLikeDeclaration,
224
checker: ts.TypeChecker
225
): ts.Type;
226
227
/**
228
* Get instance type of class-like declaration
229
* @param node - Class-like declaration
230
* @param checker - Type checker instance
231
* @returns Instance type
232
*/
233
function getInstanceTypeOfClassLikeDeclaration(
234
node: ts.ClassLikeDeclaration,
235
checker: ts.TypeChecker
236
): ts.Type;
237
238
/**
239
* Get base class member symbol for class element
240
* @param node - Class member declaration
241
* @param checker - Type checker instance
242
* @returns Base class member symbol if found
243
*/
244
function getBaseClassMemberOfClassElement(
245
node: ts.PropertyDeclaration | ts.MethodDeclaration | ts.AccessorDeclaration,
246
checker: ts.TypeChecker
247
): ts.Symbol | undefined;
248
```
249
250
### Signature Analysis
251
252
Utilities for analyzing function and method signatures.
253
254
```typescript { .api }
255
/**
256
* Get call signatures from type
257
* @param type - Type to analyze
258
* @returns Array of call signatures
259
*/
260
function getCallSignaturesOfType(type: ts.Type): ReadonlyArray<ts.Signature>;
261
```
262
263
### Iterator Type Analysis
264
265
Utilities for analyzing iterator types and async iterators.
266
267
```typescript { .api }
268
/**
269
* Extract yield result type from iterator result type
270
* @param type - Iterator result type
271
* @param node - Node for context
272
* @param checker - Type checker instance
273
* @returns Yield result type
274
*/
275
function getIteratorYieldResultFromIteratorResult(
276
type: ts.Type,
277
node: ts.Node,
278
checker: ts.TypeChecker
279
): ts.Type;
280
```
281
282
**Usage Examples:**
283
284
```typescript
285
import * as ts from "typescript";
286
import {
287
isTypeAssignableToNumber,
288
isTypeAssignableToString,
289
isFalsyType,
290
unionTypeParts,
291
getPropertyOfType,
292
getSymbolOfClassLikeDeclaration,
293
getCallSignaturesOfType,
294
isThenableType
295
} from "tsutils/util";
296
297
// Type assignability analysis
298
function analyzeTypeCompatibility(checker: ts.TypeChecker, type: ts.Type) {
299
if (isTypeAssignableToNumber(checker, type)) {
300
console.log("Type is assignable to number");
301
}
302
303
if (isTypeAssignableToString(checker, type)) {
304
console.log("Type is assignable to string");
305
}
306
307
if (isFalsyType(type)) {
308
console.log("Type is always falsy");
309
}
310
}
311
312
// Union type analysis
313
function analyzeUnionType(checker: ts.TypeChecker, type: ts.Type) {
314
if (type.flags & ts.TypeFlags.Union) {
315
const parts = unionTypeParts(type);
316
console.log(`Union has ${parts.length} parts:`);
317
318
parts.forEach((part, index) => {
319
console.log(` ${index}: ${checker.typeToString(part)}`);
320
321
if (isTypeAssignableToString(checker, part)) {
322
console.log(` Part ${index} is string-like`);
323
}
324
});
325
}
326
}
327
328
// Property analysis
329
function analyzeTypeProperties(checker: ts.TypeChecker, type: ts.Type) {
330
if (type.symbol && type.symbol.members) {
331
console.log("Type properties:");
332
333
type.symbol.members.forEach((symbol, name) => {
334
const property = getPropertyOfType(type, name);
335
if (property) {
336
console.log(` ${name}: ${checker.typeToString(checker.getTypeOfSymbolAtLocation(property, property.valueDeclaration!))}`);
337
338
if (isPropertyReadonlyInType(type, name, checker)) {
339
console.log(` (readonly)`);
340
}
341
}
342
});
343
}
344
}
345
346
// Class analysis
347
function analyzeClass(checker: ts.TypeChecker, classDecl: ts.ClassDeclaration) {
348
const symbol = getSymbolOfClassLikeDeclaration(classDecl, checker);
349
const constructorType = getConstructorTypeOfClassLikeDeclaration(classDecl, checker);
350
const instanceType = getInstanceTypeOfClassLikeDeclaration(classDecl, checker);
351
352
console.log(`Class: ${symbol.name}`);
353
console.log(`Constructor type: ${checker.typeToString(constructorType)}`);
354
console.log(`Instance type: ${checker.typeToString(instanceType)}`);
355
356
// Analyze class members
357
classDecl.members.forEach(member => {
358
if (ts.isPropertyDeclaration(member) || ts.isMethodDeclaration(member) || ts.isGetAccessorDeclaration(member)) {
359
const baseSymbol = getBaseClassMemberOfClassElement(member, checker);
360
if (baseSymbol) {
361
console.log(`Member ${member.name?.getText()} overrides base class member`);
362
}
363
}
364
});
365
}
366
367
// Function type analysis
368
function analyzeFunctionType(checker: ts.TypeChecker, type: ts.Type) {
369
const signatures = getCallSignaturesOfType(type);
370
371
if (signatures.length > 0) {
372
console.log(`Function has ${signatures.length} call signature(s):`);
373
374
signatures.forEach((sig, index) => {
375
const sigString = checker.signatureToString(sig);
376
console.log(` ${index}: ${sigString}`);
377
378
const returnType = sig.getReturnType();
379
if (isThenableType(checker, sig.declaration!, returnType)) {
380
console.log(` Returns Promise-like type`);
381
}
382
});
383
}
384
}
385
386
// Promise/thenable analysis
387
function analyzeAsyncTypes(checker: ts.TypeChecker, node: ts.Expression) {
388
const type = checker.getTypeAtLocation(node);
389
390
if (isThenableType(checker, node, type)) {
391
console.log("Expression is thenable (Promise-like)");
392
393
// Try to get the resolved type
394
const thenProperty = getPropertyOfType(type, 'then' as ts.__String);
395
if (thenProperty) {
396
const thenType = checker.getTypeOfSymbolAtLocation(thenProperty, node);
397
console.log(`Then method type: ${checker.typeToString(thenType)}`);
398
}
399
}
400
}
401
402
// Complex type analysis combining multiple utilities
403
function performDeepTypeAnalysis(checker: ts.TypeChecker, type: ts.Type, node: ts.Node) {
404
console.log(`\nAnalyzing type: ${checker.typeToString(type)}`);
405
406
// Basic classification
407
if (isFalsyType(type)) {
408
console.log(" Type is falsy");
409
}
410
411
if (isEmptyObjectType(type)) {
412
console.log(" Type is empty object");
413
}
414
415
// Composite type analysis
416
if (type.flags & ts.TypeFlags.Union) {
417
const parts = unionTypeParts(type);
418
console.log(` Union with ${parts.length} parts`);
419
420
const stringParts = parts.filter(p => isTypeAssignableToString(checker, p));
421
const numberParts = parts.filter(p => isTypeAssignableToNumber(checker, p));
422
423
console.log(` String-assignable parts: ${stringParts.length}`);
424
console.log(` Number-assignable parts: ${numberParts.length}`);
425
}
426
427
// Callable analysis
428
const signatures = getCallSignaturesOfType(type);
429
if (signatures.length > 0) {
430
console.log(` Callable with ${signatures.length} signature(s)`);
431
432
const asyncSignatures = signatures.filter(sig => {
433
const returnType = sig.getReturnType();
434
return isThenableType(checker, node, returnType);
435
});
436
437
if (asyncSignatures.length > 0) {
438
console.log(` ${asyncSignatures.length} async signature(s)`);
439
}
440
}
441
}
442
```
443
444
**Advanced Use Cases:**
445
446
1. **Type-aware Refactoring**: Understanding type relationships for safe code transformations
447
2. **API Compatibility Checking**: Verifying type compatibility across API versions
448
3. **Generic Type Resolution**: Working with complex generic types and constraints
449
4. **Promise/Async Analysis**: Detecting and analyzing asynchronous code patterns
450
5. **Class Hierarchy Analysis**: Understanding inheritance and member overrides
451
6. **Property Mutation Detection**: Identifying readonly vs mutable properties
452
7. **Type Narrowing**: Building sophisticated type guards and narrowing logic
453
8. **Iterator Pattern Analysis**: Working with iterables and async iterables