Utility functions for working with TypeScript's API, providing comprehensive tools for analyzing and manipulating TypeScript AST nodes, types, and compiler APIs.
npx @tessl/cli install tessl/npm-ts-api-utils@2.0.00
# ts-api-utils
1
2
A comprehensive collection of utility functions for working with TypeScript's API. This library serves as the successor to the popular `tsutils` library, providing a modern, well-typed toolkit for building TypeScript tooling, linters, code analyzers, and other developer tools that need to work with TypeScript's Abstract Syntax Tree (AST).
3
4
## Package Information
5
6
- **Package Name**: `ts-api-utils`
7
- **Version**: 2.0.0
8
- **Language**: TypeScript (compiled to JavaScript)
9
- **License**: MIT
10
- **Repository**: [github.com/JoshuaKGoldberg/ts-api-utils](https://github.com/JoshuaKGoldberg/ts-api-utils)
11
- **Minimum TypeScript Version**: 4.8.4
12
- **Node Version**: >=18.12
13
14
### Installation
15
16
```bash
17
npm install ts-api-utils
18
```
19
20
### Core Imports
21
22
The library supports both ESM and CommonJS imports:
23
24
```typescript { .api }
25
// ESM import (recommended)
26
import * as tsutils from "ts-api-utils";
27
28
// Named imports
29
import {
30
forEachToken,
31
isBlockStatement,
32
getCallSignaturesOfType,
33
collectVariableUsage,
34
isTsVersionAtLeast
35
} from "ts-api-utils";
36
37
// CommonJS (legacy)
38
const tsutils = require("ts-api-utils");
39
```
40
41
## Basic Usage
42
43
ts-api-utils provides utilities that work seamlessly with TypeScript's compiler API:
44
45
```typescript { .api }
46
import * as ts from "typescript";
47
import { forEachToken, isBlockStatement, getCallSignaturesOfType } from "ts-api-utils";
48
49
// Example: Iterate over all tokens in a node
50
function analyzeNode(node: ts.Node, sourceFile: ts.SourceFile) {
51
forEachToken(node, (token) => {
52
console.log(`Token: ${ts.SyntaxKind[token.kind]}`);
53
}, sourceFile);
54
}
55
56
// Example: Type-safe node checking
57
function processStatement(node: ts.Node) {
58
if (isBlockStatement(node)) {
59
// TypeScript now knows 'node' is a BlockStatement
60
console.log(`Block has ${node.statements.length} statements`);
61
}
62
}
63
64
// Example: Working with type information
65
function analyzeType(type: ts.Type) {
66
const signatures = getCallSignaturesOfType(type);
67
if (signatures.length > 0) {
68
console.log(`Type has ${signatures.length} call signatures`);
69
}
70
}
71
```
72
73
## Architecture
74
75
ts-api-utils is organized into logical modules that mirror different aspects of TypeScript analysis:
76
77
### Core Design Patterns
78
79
1. **Type Guards**: Functions that narrow TypeScript types (e.g., `isBlockStatement`)
80
2. **Analyzers**: Functions that extract information from AST nodes (e.g., `getAccessKind`)
81
3. **Utilities**: Helper functions for common operations (e.g., `forEachToken`)
82
4. **Collectors**: Functions that gather data across larger code structures (e.g., `collectVariableUsage`)
83
84
### Module Organization
85
86
The library is structured around these main capability areas:
87
88
- **Node Analysis**: The largest module, containing type guards for every TypeScript node type
89
- **Type System Utilities**: Second largest module, providing deep integration with TypeScript's type system
90
- **Usage Analysis**: Advanced scope and variable tracking capabilities
91
- **Token Processing**: Low-level token iteration and manipulation
92
- **Syntax Utilities**: Common syntax analysis patterns
93
- **Compiler Integration**: Working with compiler options and flags
94
- **Comment Processing**: Extracting and working with code comments
95
- **Scope Analysis**: Understanding scope boundaries and relationships
96
- **Modifier Utilities**: Working with TypeScript modifiers
97
98
## Capabilities
99
100
### Comments Processing
101
102
Working with TypeScript comments attached to AST nodes.
103
104
**When to use**: Extract documentation, analyze comment patterns, or build tools that need to preserve or manipulate comments during code transformations.
105
106
```typescript { .api }
107
import { forEachComment, ForEachCommentCallback } from "ts-api-utils";
108
109
// Callback for processing each comment
110
type ForEachCommentCallback = (fullText: string, comment: ts.CommentRange) => void;
111
112
// Iterate over all comments owned by a node or its children
113
function forEachComment(
114
node: ts.Node,
115
callback: ForEachCommentCallback,
116
sourceFile?: ts.SourceFile
117
): void;
118
```
119
120
[Syntax Utilities Guide](./syntax-utilities.md)
121
122
### Compiler Options
123
124
Analyzing and testing TypeScript compiler configuration settings.
125
126
**When to use**: Build tools that need to understand compiler settings, validate configurations, or provide different behavior based on strict mode settings.
127
128
```typescript { .api }
129
import {
130
isCompilerOptionEnabled,
131
isStrictCompilerOptionEnabled,
132
BooleanCompilerOptions,
133
StrictCompilerOption
134
} from "ts-api-utils";
135
136
// Options that can be tested with isCompilerOptionEnabled
137
type BooleanCompilerOptions = keyof {
138
[K in keyof ts.CompilerOptions as NonNullable<ts.CompilerOptions[K]> extends boolean ? K : never]: unknown;
139
};
140
141
// Strict mode options
142
type StrictCompilerOption =
143
| "alwaysStrict"
144
| "noImplicitAny"
145
| "noImplicitThis"
146
| "strictBindCallApply"
147
| "strictFunctionTypes"
148
| "strictNullChecks"
149
| "strictPropertyInitialization";
150
151
// Check if a compiler option is enabled (handles option dependencies)
152
function isCompilerOptionEnabled(
153
options: ts.CompilerOptions,
154
option: BooleanCompilerOptions
155
): boolean;
156
157
// Check strict mode options (accounts for global strict setting)
158
function isStrictCompilerOptionEnabled(
159
options: ts.CompilerOptions,
160
option: StrictCompilerOption
161
): boolean;
162
```
163
164
[Compiler Options Guide](./compiler-options.md)
165
166
### Flag Utilities
167
168
Testing various TypeScript flags on nodes, types, and symbols.
169
170
**When to use**: Determine node characteristics, check type properties, or analyze symbol metadata in static analysis tools.
171
172
```typescript { .api }
173
import {
174
isModifierFlagSet,
175
isNodeFlagSet,
176
isObjectFlagSet,
177
isSymbolFlagSet,
178
isTypeFlagSet
179
} from "ts-api-utils";
180
181
// Test modifier flags on declarations
182
function isModifierFlagSet(node: ts.Declaration, flag: ts.ModifierFlags): boolean;
183
184
// Test node flags
185
function isNodeFlagSet(node: ts.Node, flag: ts.NodeFlags): boolean;
186
187
// Test object type flags
188
function isObjectFlagSet(objectType: ts.ObjectType, flag: ts.ObjectFlags): boolean;
189
190
// Test symbol flags
191
function isSymbolFlagSet(symbol: ts.Symbol, flag: ts.SymbolFlags): boolean;
192
193
// Test type flags
194
function isTypeFlagSet(type: ts.Type, flag: ts.TypeFlags): boolean;
195
```
196
197
[Flag Utilities Guide](./syntax-utilities.md)
198
199
### Modifier Utilities
200
201
Working with TypeScript modifier tokens like `public`, `private`, `static`, etc.
202
203
**When to use**: Analyze access modifiers, check for specific modifiers, or build tools that need to understand declaration visibility.
204
205
```typescript { .api }
206
import { includesModifier } from "ts-api-utils";
207
208
// Test if modifiers include any of the given kinds
209
function includesModifier(
210
modifiers: Iterable<ts.ModifierLike> | undefined,
211
...kinds: ts.ModifierSyntaxKind[]
212
): boolean;
213
```
214
215
[Modifier Utilities Guide](./syntax-utilities.md)
216
217
### Node Analysis
218
219
The most comprehensive module providing type guards and utilities for every TypeScript AST node type.
220
221
**When to use**: This is the core of most TypeScript analysis tools. Use these functions whenever you need to safely narrow node types, check node properties, or traverse the AST with type safety.
222
223
```typescript { .api }
224
import {
225
isBlockStatement,
226
isVariableDeclaration,
227
isIterationStatement,
228
isNamedDeclarationWithName,
229
isConstAssertionExpression,
230
hasModifiers,
231
hasType,
232
isAccessExpression,
233
getAccessKind,
234
AccessKind
235
} from "ts-api-utils";
236
237
// Access patterns for expressions
238
enum AccessKind {
239
None = 0,
240
Read = 1,
241
Write = 2,
242
Delete = 4,
243
ReadWrite = 3
244
}
245
246
// Type guards for compound node types
247
interface NamedDeclarationWithName extends ts.NamedDeclaration {
248
readonly name: ts.DeclarationName;
249
}
250
251
interface ConstAssertionExpression extends ts.AssertionExpression {
252
readonly type: ts.TypeNode & { readonly typeName: ConstAssertionIdentifier };
253
}
254
255
// Essential node type guards
256
function isBlockStatement(node: ts.Node): node is ts.BlockStatement;
257
function isVariableDeclaration(node: ts.Node): node is ts.VariableDeclaration;
258
function isIterationStatement(node: ts.Node): node is ts.IterationStatement;
259
function isNamedDeclarationWithName(node: ts.Declaration): node is NamedDeclarationWithName;
260
261
// Property-based type guards
262
function hasModifiers(node: ts.Node): node is ts.HasModifiers;
263
function hasType(node: ts.Node): node is ts.HasType;
264
function isAccessExpression(node: ts.Node): node is ts.AccessExpression;
265
266
// Expression analysis
267
function getAccessKind(node: ts.Expression): AccessKind;
268
```
269
270
[Node Analysis Guide](./node-analysis.md)
271
272
### Scope Analysis
273
274
Determining scope boundaries and understanding lexical scoping in TypeScript.
275
276
**When to use**: Build variable tracking tools, analyze closure behavior, or implement scope-aware refactoring tools.
277
278
```typescript { .api }
279
import { isFunctionScopeBoundary } from "ts-api-utils";
280
281
// Check if a node creates a function scope boundary
282
function isFunctionScopeBoundary(node: ts.Node): boolean;
283
```
284
285
[Scope Analysis Guide](./syntax-utilities.md)
286
287
### Syntax Utilities
288
289
General utilities for common syntax analysis patterns.
290
291
**When to use**: Validate identifiers, check assignment patterns, or analyze property access expressions.
292
293
```typescript { .api }
294
import {
295
isAssignmentKind,
296
isNumericPropertyName,
297
isValidPropertyAccess
298
} from "ts-api-utils";
299
300
// Test if a syntax kind represents assignment
301
function isAssignmentKind(kind: ts.SyntaxKind): boolean;
302
303
// Test if a string is a numeric property name
304
function isNumericPropertyName(name: string | ts.__String): boolean;
305
306
// Check if text can be used in property access expressions
307
function isValidPropertyAccess(text: string, languageVersion?: ts.ScriptTarget): boolean;
308
```
309
310
[Syntax Utilities Guide](./syntax-utilities.md)
311
312
### Token Processing
313
314
Low-level iteration and manipulation of tokens in TypeScript source code.
315
316
**When to use**: Build formatters, implement custom syntax highlighting, or perform detailed source code analysis that needs to examine every token.
317
318
```typescript { .api }
319
import { forEachToken, ForEachTokenCallback } from "ts-api-utils";
320
321
// Callback for processing each token
322
type ForEachTokenCallback = (token: ts.Node) => void;
323
324
// Iterate over all tokens of a node
325
function forEachToken(
326
node: ts.Node,
327
callback: ForEachTokenCallback,
328
sourceFile?: ts.SourceFile
329
): void;
330
```
331
332
[Token Processing Guide](./syntax-utilities.md)
333
334
### Type System Utilities
335
336
Comprehensive utilities for working with TypeScript's type system, including type analysis, type guards, and type manipulation.
337
338
**When to use**: Build type-aware linting rules, analyze type relationships, implement type-based refactoring tools, or create tools that need deep integration with TypeScript's type checker.
339
340
```typescript { .api }
341
import {
342
getCallSignaturesOfType,
343
getPropertyOfType,
344
intersectionTypeParts,
345
unionTypeParts,
346
typeParts,
347
isFalsyType,
348
isThenableType,
349
typeIsLiteral,
350
isPropertyReadonlyInType,
351
symbolHasReadonlyDeclaration,
352
isConditionalType,
353
isEnumType,
354
isIndexedAccessType,
355
isIntersectionType,
356
isUnionType,
357
isObjectType,
358
isTupleType,
359
isTypeReference,
360
isBooleanLiteralType,
361
isBigIntLiteralType,
362
isStringLiteralType,
363
isNumberLiteralType
364
} from "ts-api-utils";
365
366
// Type information retrieval
367
function getCallSignaturesOfType(type: ts.Type): readonly ts.Signature[];
368
function getPropertyOfType(type: ts.Type, name: ts.__String): ts.Symbol | undefined;
369
370
// Type decomposition utilities
371
function intersectionTypeParts(type: ts.Type): ts.Type[];
372
function unionTypeParts(type: ts.Type): ts.Type[];
373
function typeParts(type: ts.Type): ts.Type[];
374
375
// Type analysis utilities
376
function isFalsyType(type: ts.Type): boolean;
377
function isThenableType(typeChecker: ts.TypeChecker, node: ts.Node, type: ts.Type): boolean;
378
function typeIsLiteral(type: ts.Type): type is ts.LiteralType;
379
function isPropertyReadonlyInType(
380
type: ts.Type,
381
name: ts.__String,
382
typeChecker: ts.TypeChecker
383
): boolean;
384
385
// Symbol utilities
386
function symbolHasReadonlyDeclaration(symbol: ts.Symbol, typeChecker: ts.TypeChecker): boolean;
387
388
// Core type guards
389
function isConditionalType(type: ts.Type): type is ts.ConditionalType;
390
function isEnumType(type: ts.Type): type is ts.EnumType;
391
function isIndexedAccessType(type: ts.Type): type is ts.IndexedAccessType;
392
function isIntersectionType(type: ts.Type): type is ts.IntersectionType;
393
function isUnionType(type: ts.Type): type is ts.UnionType;
394
function isObjectType(type: ts.Type): type is ts.ObjectType;
395
396
// Object type utilities
397
function isTupleType(type: ts.Type): type is ts.TupleType;
398
function isTypeReference(type: ts.Type): type is ts.TypeReference;
399
400
// Literal type guards
401
function isBooleanLiteralType(type: ts.Type): type is ts.LiteralType;
402
function isBigIntLiteralType(type: ts.Type): type is ts.BigIntLiteralType;
403
function isStringLiteralType(type: ts.Type): type is ts.StringLiteralType;
404
function isNumberLiteralType(type: ts.Type): type is ts.NumberLiteralType;
405
```
406
407
[Type System Guide](./type-system.md)
408
409
### Usage Analysis
410
411
Advanced analysis of variable and symbol usage patterns, including scope tracking and declaration analysis.
412
413
**When to use**: Build unused variable detectors, implement variable renaming tools, analyze variable lifecycle, or create tools that need comprehensive understanding of identifier usage across scopes.
414
415
```typescript { .api }
416
import {
417
collectVariableUsage,
418
UsageInfo,
419
Usage,
420
DeclarationDomain,
421
UsageDomain,
422
isBlockScopeBoundary,
423
ScopeBoundary,
424
getDeclarationDomain,
425
getUsageDomain,
426
identifierToKeywordKind
427
} from "ts-api-utils";
428
429
// Usage domains (type vs value space)
430
enum DeclarationDomain {
431
Namespace = 1,
432
Type = 2,
433
Value = 4,
434
Any = 7,
435
Import = 8
436
}
437
438
enum UsageDomain {
439
Namespace = 1,
440
Type = 2,
441
Value = 4,
442
Any = 7,
443
TypeQuery = 8,
444
ValueOrNamespace = 5
445
}
446
447
// Usage tracking interfaces
448
interface Usage {
449
readonly domain: UsageDomain;
450
readonly location: ts.Identifier;
451
}
452
453
interface UsageInfo {
454
readonly declarations: ts.Identifier[];
455
readonly domain: DeclarationDomain;
456
readonly exported: boolean;
457
readonly inGlobalScope: boolean;
458
readonly uses: Usage[];
459
}
460
461
// Scope boundary analysis
462
enum ScopeBoundary {
463
None = 0,
464
Function = 1,
465
Block = 2,
466
Type = 4,
467
ConditionalType = 8
468
}
469
470
// Main usage collection function
471
function collectVariableUsage(sourceFile: ts.SourceFile): Map<ts.Identifier, UsageInfo>;
472
473
// Scope and domain analysis functions
474
function isBlockScopeBoundary(node: ts.Node): ScopeBoundary;
475
function getDeclarationDomain(node: ts.Identifier): DeclarationDomain | undefined;
476
function getUsageDomain(node: ts.Identifier): UsageDomain | undefined;
477
478
// TypeScript version compatibility utility
479
function identifierToKeywordKind(node: ts.Identifier): ts.SyntaxKind | undefined;
480
```
481
482
[Usage Analysis Guide](./usage-analysis.md)
483
484
### Utility Functions
485
486
General utility functions for TypeScript version compatibility and common operations.
487
488
**When to use**: Check TypeScript version compatibility for feature detection, or perform version-specific operations.
489
490
```typescript { .api }
491
import { isTsVersionAtLeast } from "ts-api-utils";
492
493
// Check if the current TypeScript version is at least the specified version
494
function isTsVersionAtLeast(major: number, minor?: number): boolean;
495
```
496
497
## Related Libraries
498
499
ts-api-utils works best when combined with:
500
501
- **TypeScript Compiler API**: The foundation that ts-api-utils extends
502
- **@typescript-eslint/utils**: For building ESLint rules with TypeScript support
503
- **ts-morph**: Higher-level TypeScript manipulation library
504
- **typescript**: The TypeScript compiler itself (peer dependency)
505
506
## Best Practices
507
508
1. **Always use type guards**: The library's type guards provide essential type safety when working with AST nodes
509
2. **Leverage the type system**: Functions are designed to work seamlessly with TypeScript's type inference
510
3. **Combine utilities**: Most real-world use cases benefit from combining multiple utilities (e.g., node analysis + type checking + usage analysis)
511
4. **Cache results**: For performance-critical applications, consider caching results of expensive operations like `collectVariableUsage`
512
5. **Use with source files**: Many functions work better when provided with the source file context
513
514
## Performance Considerations
515
516
- **Usage analysis**: `collectVariableUsage` is the most expensive operation; use judiciously for large files
517
- **Type operations**: Type-related utilities require a TypeChecker instance; reuse when possible
518
- **Token iteration**: `forEachToken` can be expensive for very large nodes; consider targeted analysis instead
519
- **Scope analysis**: Scope boundary detection is generally fast and safe to use liberally
520
521
ts-api-utils provides the essential building blocks for any serious TypeScript tooling project, offering both low-level token manipulation and high-level semantic analysis capabilities.