TypeScript scope analyser for ESLint that provides comprehensive scope analysis capabilities for JavaScript and TypeScript code
—
The scope type system provides comprehensive coverage of all JavaScript and TypeScript language constructs with specialized behavior for each scope type.
The main Scope type that represents all possible scope types in the system.
type Scope =
| BlockScope
| CatchScope
| ClassScope
| ClassFieldInitializerScope
| ClassStaticBlockScope
| ConditionalTypeScope
| ForScope
| FunctionScope
| FunctionExpressionNameScope
| FunctionTypeScope
| GlobalScope
| MappedTypeScope
| ModuleScope
| SwitchScope
| TSEnumScope
| TSModuleScope
| TypeScope
| WithScope;Enumeration of all scope type identifiers used throughout the system.
enum ScopeType {
block = "block",
catch = "catch",
class = "class",
classFieldInitializer = "class-field-initializer",
classStaticBlock = "class-static-block",
conditionalType = "conditionalType",
for = "for",
function = "function",
functionExpressionName = "function-expression-name",
functionType = "functionType",
global = "global",
mappedType = "mappedType",
module = "module",
switch = "switch",
tsEnum = "tsEnum",
tsModule = "tsModule",
type = "type",
with = "with"
}All scopes extend from a common base that provides essential scope functionality.
interface ScopeBase {
/** Unique identifier for this scope instance */
readonly $id: number;
/** The AST node that created this scope */
readonly block: TSESTree.Node;
/** Child scopes contained within this scope */
readonly childScopes: Scope[];
/** Whether this scope is associated with a function expression name */
functionExpressionScope: boolean;
/** Whether this scope is in strict mode */
isStrict: boolean;
/** References to identifiers that cross scope boundaries */
readonly references: Reference[];
/** Set of variables defined directly in this scope */
readonly set: Map<string, Variable>;
/** References that could not be resolved in this scope */
readonly through: Reference[];
/** The type of this scope */
readonly type: ScopeType;
/** The parent scope containing this scope */
readonly upper: Scope | null;
/** All variables accessible in this scope */
readonly variables: Variable[];
/** The scope where var declarations are hoisted to */
readonly variableScope: Scope;
}Scope created by block statements, including if/else blocks, try/catch blocks, and standalone block statements.
class BlockScope extends ScopeBase {
readonly type: ScopeType.block;
readonly block: TSESTree.BlockStatement;
}Usage Examples:
// Block scopes are created for:
{
let x = 1; // BlockScope variables
const y = 2;
}
if (condition) {
let z = 3; // Another BlockScope
}
try {
let a = 4; // BlockScope within try
} catch (e) {
// CatchScope (separate type)
}Scope created by catch clauses in try-catch statements.
class CatchScope extends ScopeBase {
readonly type: ScopeType.catch;
readonly block: TSESTree.CatchClause;
}Scope created by for loop initialization sections.
class ForScope extends ScopeBase {
readonly type: ScopeType.for;
readonly block: TSESTree.ForStatement | TSESTree.ForInStatement | TSESTree.ForOfStatement;
}Usage Examples:
// ForScope created for loop variable declarations
for (let i = 0; i < 10; i++) {
// 'i' is in ForScope
// Loop body creates BlockScope
}
for (const item of items) {
// 'item' is in ForScope
}Scope created by function declarations and expressions.
class FunctionScope extends ScopeBase {
readonly type: ScopeType.function;
readonly block: TSESTree.Function;
readonly isMethodDefinition: boolean;
}Special scope for named function expressions.
class FunctionExpressionNameScope extends ScopeBase {
readonly type: ScopeType.functionExpressionName;
readonly block: TSESTree.FunctionExpression;
}Usage Examples:
// FunctionExpressionNameScope for the name 'factorial'
const f = function factorial(n) {
return n <= 1 ? 1 : n * factorial(n - 1); // 'factorial' accessible here
};
// 'factorial' not accessible hereThe root scope containing global variables and functions.
class GlobalScope extends ScopeBase {
readonly type: ScopeType.global;
readonly block: TSESTree.Program;
/** Define an implicit global variable */
defineImplicitVariable(name: string, options: ImplicitGlobalVariableOptions): void;
}Scope created by ES modules (when sourceType is 'module').
class ModuleScope extends ScopeBase {
readonly type: ScopeType.module;
readonly block: TSESTree.Program;
}Scope created by switch statements.
class SwitchScope extends ScopeBase {
readonly type: ScopeType.switch;
readonly block: TSESTree.SwitchStatement;
}Scope created by with statements (deprecated feature).
class WithScope extends ScopeBase {
readonly type: ScopeType.with;
readonly block: TSESTree.WithStatement;
}Scope created by class declarations and expressions.
class ClassScope extends ScopeBase {
readonly type: ScopeType.class;
readonly block: TSESTree.ClassDeclaration | TSESTree.ClassExpression;
}Scope created by class field initializers.
class ClassFieldInitializerScope extends ScopeBase {
readonly type: ScopeType.classFieldInitializer;
readonly block: TSESTree.PropertyDefinition;
}Scope created by class static blocks.
class ClassStaticBlockScope extends ScopeBase {
readonly type: ScopeType.classStaticBlock;
readonly block: TSESTree.StaticBlock;
}Usage Examples:
class MyClass {
// ClassFieldInitializerScope
field = this.getValue();
static {
// ClassStaticBlockScope
console.log('Static block');
}
getValue() {
// FunctionScope (method)
return 42;
}
}General scope for TypeScript type constructs.
class TypeScope extends ScopeBase {
readonly type: ScopeType.type;
readonly block: TSESTree.TSTypeAnnotation | TSESTree.TSTypeParameter;
}Scope created by function type annotations.
class FunctionTypeScope extends ScopeBase {
readonly type: ScopeType.functionType;
readonly block: TSESTree.TSFunctionType | TSESTree.TSConstructorType;
}Scope created by conditional type expressions.
class ConditionalTypeScope extends ScopeBase {
readonly type: ScopeType.conditionalType;
readonly block: TSESTree.TSConditionalType;
}Scope created by mapped type expressions.
class MappedTypeScope extends ScopeBase {
readonly type: ScopeType.mappedType;
readonly block: TSESTree.TSMappedType;
}Scope created by TypeScript enum declarations.
class TSEnumScope extends ScopeBase {
readonly type: ScopeType.tsEnum;
readonly block: TSESTree.TSEnumDeclaration;
}Scope created by TypeScript module (namespace) declarations.
class TSModuleScope extends ScopeBase {
readonly type: ScopeType.tsModule;
readonly block: TSESTree.TSModuleDeclaration;
}Usage Examples:
// TSEnumScope
enum Color {
Red, // Each member creates definitions
Green,
Blue
}
// TSModuleScope
namespace Utilities {
export function helper() {
// FunctionScope within TSModuleScope
}
}
// Conditional and mapped types
type IsString<T> = T extends string ? true : false; // ConditionalTypeScope
type Readonly<T> = { readonly [K in keyof T]: T[K] }; // MappedTypeScope
// Function type scope
type Handler = (event: Event) => void; // FunctionTypeScope// Common patterns for working with scopes
function analyzeScope(scope: Scope) {
console.log(`Scope type: ${scope.type}`);
// Type-specific handling
switch (scope.type) {
case ScopeType.function:
const funcScope = scope as FunctionScope;
console.log(`Method definition: ${funcScope.isMethodDefinition}`);
break;
case ScopeType.class:
const classScope = scope as ClassScope;
console.log(`Class scope with ${classScope.variables.length} variables`);
break;
case ScopeType.tsEnum:
const enumScope = scope as TSEnumScope;
console.log(`Enum scope: ${enumScope.block.id?.name}`);
break;
}
// Navigate hierarchy
if (scope.upper) {
console.log(`Parent: ${scope.upper.type}`);
}
scope.childScopes.forEach(child => {
console.log(`Child: ${child.type}`);
});
}Install with Tessl CLI
npx tessl i tessl/npm-typescript-eslint--scope-manager