Utility functions for working with TypeScript's Abstract Syntax Tree (AST) and type system
—
Advanced analysis utilities for scope boundaries, variable declarations, control flow, import/export analysis, modifier checking, and compiler option validation. These functions provide deep insights into TypeScript code structure and behavior.
Utilities for analyzing TypeScript modifiers on declarations and class members.
/**
* Get specific modifier from a node
* @param node - Node to check for modifier
* @param kind - Type of modifier to find
* @returns Modifier node if found, undefined otherwise
*/
function getModifier(node: ts.Node, kind: ts.Modifier['kind']): ts.Modifier | undefined;
/**
* Check if node has any of the specified modifiers
* @param modifiers - Modifiers array to check
* @param kinds - Modifier kinds to look for
* @returns true if any of the specified modifiers are present
*/
function hasModifier(modifiers: ts.ModifiersArray | undefined, ...kinds: Array<ts.Modifier['kind']>): boolean;
/**
* Check if parameter declaration is a parameter property
* @param node - Parameter declaration to check
* @returns true if parameter has access modifier making it a property
*/
function isParameterProperty(node: ts.ParameterDeclaration): boolean;
/**
* Check if node has access modifier (public, private, protected)
* @param node - Class element or parameter to check
* @returns true if node has access modifier
*/
function hasAccessModifier(node: ts.ClassElement | ts.ParameterDeclaration): boolean;
/**
* Check if parameter is the 'this' parameter
* @param parameter - Parameter declaration to check
* @returns true if parameter represents 'this'
*/
function isThisParameter(parameter: ts.ParameterDeclaration): boolean;Utilities for checking various TypeScript compiler flags on nodes, types, and symbols.
/**
* Check if node has specific node flags set
* @param node - Node to check
* @param flag - Node flags to test
* @returns true if flags are set
*/
const isNodeFlagSet: (node: ts.Node, flag: ts.NodeFlags) => boolean;
/**
* Check if type has specific type flags set
* @param type - Type to check
* @param flag - Type flags to test
* @returns true if flags are set
*/
const isTypeFlagSet: (type: ts.Type, flag: ts.TypeFlags) => boolean;
/**
* Check if symbol has specific symbol flags set
* @param symbol - Symbol to check
* @param flag - Symbol flags to test
* @returns true if flags are set
*/
const isSymbolFlagSet: (symbol: ts.Symbol, flag: ts.SymbolFlags) => boolean;
/**
* Check if object type has specific object flags set
* @param objectType - Object type to check
* @param flag - Object flags to test
* @returns true if flags are set
*/
function isObjectFlagSet(objectType: ts.ObjectType, flag: ts.ObjectFlags): boolean;
/**
* Check if node has specific modifier flags set
* @param node - Node to check
* @param flag - Modifier flags to test
* @returns true if flags are set
*/
function isModifierFlagSet(node: ts.Node, flag: ts.ModifierFlags): boolean;Utilities for analyzing variable declarations and their scoping behavior.
/**
* Get the declaration kind (var, let, const) for a variable declaration list
* @param declarationList - Variable declaration list to analyze
* @returns Declaration kind enum value
*/
function getVariableDeclarationKind(declarationList: ts.VariableDeclarationList): VariableDeclarationKind;
/**
* Check if variable declaration list is block-scoped (let/const)
* @param declarationList - Declaration list to check
* @returns true if declarations are block-scoped
*/
function isBlockScopedVariableDeclarationList(declarationList: ts.VariableDeclarationList): boolean;
/**
* Check if variable declaration is block-scoped
* @param declaration - Variable declaration to check
* @returns true if declaration is block-scoped
*/
function isBlockScopedVariableDeclaration(declaration: ts.VariableDeclaration): boolean;
/**
* Check if statement is a block-scoped declaration statement
* @param statement - Statement to check
* @returns true if statement declares block-scoped variables
*/
function isBlockScopedDeclarationStatement(statement: ts.Statement): statement is ts.DeclarationStatement;
/**
* Variable declaration kind enumeration
*/
enum VariableDeclarationKind {
Var,
Let,
Const
}Utilities for analyzing destructuring patterns and extracting identifiers.
/**
* Iterate through all identifiers in a destructuring pattern
* @param pattern - Binding pattern to analyze
* @param fn - Callback function for each identifier
* @returns Result from callback if any
*/
function forEachDestructuringIdentifier<T>(
pattern: ts.BindingPattern,
fn: (element: ts.BindingElement & { name: ts.Identifier }) => T
): T | undefined;
/**
* Iterate through all declared variables in a declaration list
* @param declarationList - Variable declaration list to analyze
* @param cb - Callback function for each declared variable
* @returns Result from callback if any
*/
function forEachDeclaredVariable<T>(
declarationList: ts.VariableDeclarationList,
cb: (element: (ts.VariableDeclaration | ts.BindingElement) & { name: ts.Identifier }) => T
): T | undefined;
/**
* Get the declaration that contains a binding element
* @param node - Binding element to find declaration for
* @returns Parent variable or parameter declaration
*/
function getDeclarationOfBindingElement(node: ts.BindingElement): ts.VariableDeclaration | ts.ParameterDeclaration;Utilities for analyzing scope boundaries and context in TypeScript code.
/**
* Determine the type of scope boundary a node represents
* @param node - Node to check
* @returns Scope boundary flags
*/
function isScopeBoundary(node: ts.Node): ScopeBoundary;
/**
* Check if node is a type scope boundary
* @param node - Node to check
* @returns Type scope boundary flags
*/
function isTypeScopeBoundary(node: ts.Node): ScopeBoundary;
/**
* Check if node is a function scope boundary
* @param node - Node to check
* @returns Function scope boundary flags
*/
function isFunctionScopeBoundary(node: ts.Node): ScopeBoundary;
/**
* Check if node is a block scope boundary
* @param node - Node to check
* @returns Block scope boundary flags
*/
function isBlockScopeBoundary(node: ts.Node): ScopeBoundary;
/**
* Check if statement is in single statement context (if/else/while body)
* @param statement - Statement to check
* @returns true if statement is not in block context
*/
function isInSingleStatementContext(statement: ts.Statement): boolean;
/**
* Scope boundary enumeration
*/
enum ScopeBoundary {
None = 0,
Function = 1,
Block = 2,
Type = 4,
ConditionalType = 8
}
/**
* Scope boundary selector for hierarchical selection
*/
enum ScopeBoundarySelector {
Function = ScopeBoundary.Function,
Block = ScopeBoundarySelector.Function | ScopeBoundary.Block,
Type = ScopeBoundarySelector.Block | ScopeBoundary.Type,
InferType = ScopeBoundary.ConditionalType
}Utilities for analyzing module import and export patterns.
/**
* Find all import string literals in a source file
* @param sourceFile - Source file to analyze
* @param kinds - Types of imports to find
* @param ignoreFileName - Whether to ignore filename-based imports
* @returns Array of import string literals
*/
function findImports(
sourceFile: ts.SourceFile,
kinds: ImportKind,
ignoreFileName?: boolean
): Array<ts.StringLiteral | ts.NoSubstitutionTemplateLiteral>;
/**
* Find all import-like nodes in a source file
* @param sourceFile - Source file to analyze
* @param kinds - Types of imports to find
* @param ignoreFileName - Whether to ignore filename-based imports
* @returns Array of import-like nodes
*/
function findImportLikeNodes(
sourceFile: ts.SourceFile,
kinds: ImportKind,
ignoreFileName?: boolean
): ImportLike[];
/**
* Union type for import-like constructs
*/
type ImportLike = ts.ImportDeclaration
| ts.ImportEqualsDeclaration & {moduleReference: ts.ExternalModuleReference}
| ts.ExportDeclaration & {moduleSpecifier: {}}
| ts.CallExpression & {expression: ts.Token<ts.SyntaxKind.ImportKeyword> | ts.Identifier & {text: 'require'}, arguments: [ts.Expression, ...ts.Expression[]]}
| ts.ImportTypeNode;
/**
* Import kind enumeration for filtering import types
*/
enum ImportKind {
ImportDeclaration = 1,
ImportEquals = 2,
ExportFrom = 4,
DynamicImport = 8,
Require = 16,
ImportType = 32,
All = ImportDeclaration | ImportEquals | ExportFrom | DynamicImport | Require | ImportType
}Utilities for analyzing function contexts and this references.
/**
* Check if node has its own 'this' reference
* @param node - Node to check
* @returns true if node establishes its own 'this' context
*/
function hasOwnThisReference(node: ts.Node): boolean;
/**
* Check if node is a function with a body
* @param node - Node to check
* @returns true if node is function-like with body property
*/
function isFunctionWithBody(node: ts.Node): node is ts.FunctionLikeDeclaration & {body: {}};
/**
* Get IIFE (Immediately Invoked Function Expression) call expression
* @param func - Function expression or arrow function
* @returns Call expression if function is immediately invoked
*/
function getIIFE(func: ts.FunctionExpression | ts.ArrowFunction): ts.CallExpression | undefined;Utilities for checking compiler options and their effects.
/**
* Check if strict compiler option is enabled
* @param options - Compiler options to check
* @param option - Specific strict option to check
* @returns true if strict option is enabled
*/
function isStrictCompilerOptionEnabled(options: ts.CompilerOptions, option: StrictCompilerOption): boolean;
/**
* Check if boolean compiler option is enabled
* @param options - Compiler options to check
* @param option - Boolean option to check
* @returns true if option is enabled
*/
function isCompilerOptionEnabled(options: ts.CompilerOptions, option: BooleanCompilerOptions | 'stripInternal'): boolean;
/**
* Type for strict compiler options
*/
type StrictCompilerOption = 'noImplicitAny' | 'noImplicitThis' | 'strictNullChecks' | 'strictFunctionTypes' | 'strictPropertyInitialization' | 'alwaysStrict' | 'strictBindCallApply';
/**
* Type for boolean compiler options
*/
type BooleanCompilerOptions = {[K in keyof ts.CompilerOptions]: NonNullable<ts.CompilerOptions[K]> extends boolean ? K : never} extends {[_ in keyof ts.CompilerOptions]: infer U} ? U : never;Utilities for analyzing ambient (declare) contexts and module blocks.
/**
* Check if statement is in ambient context
* @param node - Statement to check
* @returns true if statement is in ambient (declare) context
*/
function isStatementInAmbientContext(node: ts.Statement): boolean;
/**
* Check if node is an ambient module block
* @param node - Node to check
* @returns true if node is ambient module block
*/
function isAmbientModuleBlock(node: ts.Node): node is ts.ModuleBlock;
/**
* Check if module declaration is ambient
* @param node - Module declaration to check
* @returns true if module is ambient
*/
function isAmbientModule(node: ts.ModuleDeclaration): boolean;Usage Examples:
import * as ts from "typescript";
import {
hasModifier,
isParameterProperty,
getVariableDeclarationKind,
isScopeBoundary,
findImports,
isStrictCompilerOptionEnabled,
VariableDeclarationKind,
ScopeBoundary,
ImportKind
} from "tsutils/util";
// Modifier analysis example
function analyzeClassMember(member: ts.ClassElement) {
if (hasModifier(member.modifiers, ts.SyntaxKind.PrivateKeyword)) {
console.log("Member is private");
}
if (hasModifier(member.modifiers, ts.SyntaxKind.StaticKeyword, ts.SyntaxKind.ReadonlyKeyword)) {
console.log("Member is static or readonly");
}
}
// Parameter property detection
function analyzeConstructorParameters(constructor: ts.ConstructorDeclaration) {
constructor.parameters.forEach(param => {
if (isParameterProperty(param)) {
console.log(`Parameter ${param.name?.getText()} is also a property`);
}
});
}
// Variable declaration analysis
function analyzeVariableDeclarations(statement: ts.VariableStatement) {
const kind = getVariableDeclarationKind(statement.declarationList);
switch (kind) {
case VariableDeclarationKind.Var:
console.log("Function-scoped variables");
break;
case VariableDeclarationKind.Let:
console.log("Block-scoped mutable variables");
break;
case VariableDeclarationKind.Const:
console.log("Block-scoped immutable variables");
break;
}
}
// Scope boundary analysis
function analyzeScopeBoundaries(node: ts.Node) {
const boundary = isScopeBoundary(node);
if (boundary & ScopeBoundary.Function) {
console.log("Node creates function scope");
}
if (boundary & ScopeBoundary.Block) {
console.log("Node creates block scope");
}
if (boundary & ScopeBoundary.Type) {
console.log("Node creates type scope");
}
}
// Import analysis
function analyzeImports(sourceFile: ts.SourceFile) {
const allImports = findImports(sourceFile, ImportKind.All);
const dynamicImports = findImports(sourceFile, ImportKind.DynamicImport);
console.log(`Total imports: ${allImports.length}`);
console.log(`Dynamic imports: ${dynamicImports.length}`);
allImports.forEach(importLiteral => {
console.log(`Import: ${importLiteral.text}`);
});
}
// Compiler options checking
function checkStrictMode(options: ts.CompilerOptions) {
if (isStrictCompilerOptionEnabled(options, 'strictNullChecks')) {
console.log("Strict null checks enabled");
}
if (isStrictCompilerOptionEnabled(options, 'noImplicitAny')) {
console.log("No implicit any enabled");
}
}Install with Tessl CLI
npx tessl i tessl/npm-tsutils