(Experimental) Utilities for working with TypeScript + ESLint together
npx @tessl/cli install tessl/npm-typescript-eslint--experimental-utils@5.62.0@typescript-eslint/experimental-utils provides utilities for working with TypeScript and ESLint together. This package is a pure re-export of @typescript-eslint/utils and serves as a transitional compatibility layer for existing code that imports from the experimental package name.
npm install @typescript-eslint/experimental-utilsimport {
ASTUtils,
ESLintUtils,
TSESLint,
TSESTree,
TSESLintScope,
JSONSchema
} from "@typescript-eslint/experimental-utils";For CommonJS:
const {
ASTUtils,
ESLintUtils,
TSESLint,
TSESTree
} = require("@typescript-eslint/experimental-utils");import { ESLintUtils, TSESLint, ASTUtils } from "@typescript-eslint/experimental-utils";
// Create a TypeScript-aware ESLint rule
const rule = ESLintUtils.RuleCreator(name => `https://example.com/${name}`)({
name: 'my-rule',
meta: {
type: 'problem',
messages: {
error: 'Found function declaration'
},
schema: []
},
defaultOptions: [],
create(context: TSESLint.RuleContext<'error', []>) {
return {
FunctionDeclaration(node) {
if (ASTUtils.isFunction(node)) {
context.report({
node,
messageId: 'error'
});
}
}
};
}
});
// Test the rule
const ruleTester = new ESLintUtils.RuleTester({
parser: '@typescript-eslint/parser',
});
ruleTester.run('my-rule', rule, {
valid: ['const x = 1;'],
invalid: [{
code: 'function foo() {}',
errors: [{ messageId: 'error' }]
}]
});This package is purely a re-export of @typescript-eslint/utils. You should switch to importing from the non-experimental package instead:
- import { RuleCreator } from '@typescript-eslint/experimental-utils';
+ import { RuleCreator } from '@typescript-eslint/utils';The package is organized into several main modules:
Tools for manipulating and analyzing TypeScript Abstract Syntax Trees, including predicates, helpers, and pattern matching utilities.
namespace ASTUtils {
function isNodeOfType<NodeType extends TSESTree.AST_NODE_TYPES>(
nodeType: NodeType
): (node: TSESTree.Node | null | undefined) => node is Extract<TSESTree.Node, { type: NodeType }>;
function isFunction(node: TSESTree.Node | null | undefined): node is TSESTree.FunctionLike;
const LINEBREAK_MATCHER: RegExp;
function isTokenOnSameLine(
left: TSESTree.Node | TSESTree.Token,
right: TSESTree.Node | TSESTree.Token
): boolean;
}Rule creation, testing, and configuration utilities specifically designed for TypeScript ESLint rules.
namespace ESLintUtils {
function RuleCreator(urlCreator: (ruleName: string) => string): <
TOptions extends readonly unknown[],
TMessageIds extends string,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
>(ruleDefinition: Readonly<TSESLint.RuleModule<TMessageIds, TOptions, TRuleListener>>) => TSESLint.RuleModule<TMessageIds, TOptions>;
function getParserServices<TMessageIds extends string, TOptions extends readonly unknown[]>(
context: TSESLint.RuleContext<TMessageIds, TOptions>,
allowWithoutFullTypeInformation?: boolean
): TSESTree.ParserServices;
function applyDefault<TUser, TDefault>(
defaultOptions: Readonly<TDefault>,
userOptions: Readonly<TUser> | null
): TDefault;
class RuleTester {
constructor(baseOptions: TSESLint.RuleTesterConfig);
run<TMessageIds extends string, TOptions extends readonly unknown[]>(
name: string,
rule: TSESLint.RuleModule<TMessageIds, TOptions>,
tests: TSESLint.RunTests<TMessageIds, TOptions>
): void;
}
}Enhanced ESLint type definitions with full TypeScript integration for rules, contexts, and AST nodes.
namespace TSESLint {
interface RuleModule<
TMessageIds extends string,
TOptions extends readonly unknown[],
TRuleListener extends RuleListener = RuleListener
> {
meta: RuleMetaData<TMessageIds>;
create(context: RuleContext<TMessageIds, TOptions>): TRuleListener;
defaultOptions?: TOptions;
}
interface RuleContext<TMessageIds extends string, TOptions extends readonly unknown[]> {
getAncestors(): TSESTree.Node[];
getDeclaredVariables(node: TSESTree.Node): TSESLintScope.Variable[];
getFilename(): string;
getScope(): TSESLintScope.Scope;
getSourceCode(): SourceCode;
markVariableAsUsed(name: string): boolean;
report(descriptor: ReportDescriptor<TMessageIds>): void;
settings: Record<string, unknown>;
options: TOptions;
}
}AST node definitions and parser services for TypeScript syntax trees.
namespace TSESTree {
enum AST_NODE_TYPES {
ArrayExpression = 'ArrayExpression',
ArrayPattern = 'ArrayPattern',
ArrowFunctionExpression = 'ArrowFunctionExpression',
AssignmentExpression = 'AssignmentExpression',
AssignmentPattern = 'AssignmentPattern',
AwaitExpression = 'AwaitExpression',
// ... extensive enum of all AST node types
}
enum AST_TOKEN_TYPES {
Boolean = 'Boolean',
Identifier = 'Identifier',
JSXIdentifier = 'JSXIdentifier',
JSXText = 'JSXText',
Keyword = 'Keyword',
Null = 'Null',
Numeric = 'Numeric',
Punctuator = 'Punctuator',
RegularExpression = 'RegularExpression',
String = 'String',
Template = 'Template',
Block = 'Block',
Line = 'Line'
}
interface ParserServices {
program: ts.Program | null;
esTreeNodeToTSNodeMap: WeakMap<TSESTree.Node, ts.Node | ts.Token>;
tsNodeToESTreeNodeMap: WeakMap<ts.Node | ts.Token, TSESTree.Node>;
hasFullTypeInformation: boolean;
getSymbolAtLocation(node: TSESTree.Node): ts.Symbol | undefined;
getTypeAtLocation(node: TSESTree.Node): ts.Type;
}
}Utilities for analyzing variable scopes, references, and bindings in TypeScript code.
namespace TSESLintScope {
function analyze(
ast: TSESTree.Node,
options?: AnalysisOptions
): ScopeManager;
interface ScopeManager {
scopes: Scope[];
globalScope: GlobalScope | null;
acquire(node: TSESTree.Node, inner?: boolean): Scope | null;
getDeclaredVariables(node: TSESTree.Node): Variable[];
}
interface Scope {
type: ScopeType;
isStrict: boolean;
upper: Scope | null;
childScopes: Scope[];
variableScope: Scope;
block: TSESTree.Node;
variables: Variable[];
references: Reference[];
set: Map<string, Variable>;
through: Reference[];
}
const version: string;
}Complete JSON Schema type definitions for rule configuration schemas.
namespace JSONSchema {
interface JSONSchema7 {
$id?: string;
$ref?: string;
$schema?: string;
$comment?: string;
$defs?: Record<string, JSONSchema7Definition>;
title?: string;
description?: string;
default?: JSONSchema7Type;
readOnly?: boolean;
examples?: JSONSchema7Type[];
multipleOf?: number;
maximum?: number;
exclusiveMaximum?: number;
minimum?: number;
exclusiveMinimum?: number;
maxLength?: number;
minLength?: number;
pattern?: string;
additionalItems?: JSONSchema7Definition;
items?: JSONSchema7Definition | JSONSchema7Definition[];
maxItems?: number;
minItems?: number;
uniqueItems?: boolean;
contains?: JSONSchema7Definition;
maxProperties?: number;
minProperties?: number;
required?: string[];
additionalProperties?: JSONSchema7Definition;
definitions?: Record<string, JSONSchema7Definition>;
properties?: Record<string, JSONSchema7Definition>;
patternProperties?: Record<string, JSONSchema7Definition>;
dependencies?: Record<string, JSONSchema7Definition | string[]>;
propertyNames?: JSONSchema7Definition;
const?: JSONSchema7Type;
enum?: JSONSchema7Type[];
type?: JSONSchema7TypeName | JSONSchema7TypeName[];
format?: string;
contentMediaType?: string;
contentEncoding?: string;
if?: JSONSchema7Definition;
then?: JSONSchema7Definition;
else?: JSONSchema7Definition;
allOf?: JSONSchema7Definition[];
anyOf?: JSONSchema7Definition[];
oneOf?: JSONSchema7Definition[];
not?: JSONSchema7Definition;
}
type JSONSchema7Type = string | number | boolean | JSONSchema7Object | JSONSchema7Array | null;
type JSONSchema7TypeName = 'string' | 'number' | 'integer' | 'boolean' | 'object' | 'array' | 'null';
}// Core AST node union type
type Node = TSESTree.Node;
// Function-like nodes union
type FunctionLike = TSESTree.FunctionDeclaration | TSESTree.FunctionExpression | TSESTree.ArrowFunctionExpression;
// Token representation
interface Token {
type: string;
value: string;
range: [number, number];
loc: SourceLocation;
}
// Source location information
interface SourceLocation {
start: Position;
end: Position;
}
interface Position {
line: number;
column: number;
}
// Rule creation options
interface RuleMetaData<TMessageIds extends string> {
type: 'problem' | 'suggestion' | 'layout';
messages: Record<TMessageIds, string>;
fixable?: 'code' | 'whitespace';
schema: JSONSchema7 | JSONSchema7[];
deprecated?: boolean;
replacedBy?: string[];
docs?: {
description: string;
category?: string;
recommended?: boolean | 'error' | 'warn';
requiresTypeChecking?: boolean;
extendsBaseRule?: boolean | string;
};
}
// Test case definitions
interface ValidTestCase<TOptions extends readonly unknown[]> {
code: string;
options?: TOptions;
filename?: string;
parserOptions?: TSESLint.ParserOptions;
settings?: Record<string, unknown>;
parser?: string;
globals?: Record<string, boolean>;
env?: Linter.Environment;
}
interface InvalidTestCase<TMessageIds extends string, TOptions extends readonly unknown[]>
extends ValidTestCase<TOptions> {
errors: TestCaseError<TMessageIds>[];
output?: string | null;
}