An extensible static analysis linter for the TypeScript language
—
This document covers TSLint's core linting functionality, including the Linter class, programmatic usage patterns, and integration with TypeScript programs.
The Linter class is TSLint's primary interface for programmatic linting operations.
class Linter {
constructor(options: ILinterOptions, program?: ts.Program)
}interface ILinterOptions {
fix: boolean;
formatter?: string | FormatterConstructor;
formattersDirectory?: string;
quiet?: boolean;
rulesDirectory?: string | string[];
}Parameters:
options.fix - Enable automatic fixing of violationsoptions.formatter - Formatter name or constructor for output formattingoptions.formattersDirectory - Directory containing custom formattersoptions.quiet - Suppress warnings, only show errorsoptions.rulesDirectory - Directory or directories containing custom rulesprogram - Optional TypeScript program for type-aware lintinglint(fileName: string, source: string, configuration?: IConfigurationFile): voidLints a single file with the provided source code and configuration.
Parameters:
fileName - File path for error reportingsource - Source code to lintconfiguration - Optional linting configuration (uses default if not provided)Example:
import { Linter, Configuration } from 'tslint';
import * as fs from 'fs';
const linter = new Linter({ fix: false });
const config = Configuration.loadConfigurationFromPath('./tslint.json');
const source = fs.readFileSync('./src/example.ts', 'utf8');
linter.lint('./src/example.ts', source, config.results);getResult(): LintResultReturns the complete linting results after all files have been processed.
interface LintResult {
errorCount: number;
warningCount: number;
failures: RuleFailure[];
fixes?: RuleFailure[];
format: string | FormatterConstructor;
output: string;
}Example:
const result = linter.getResult();
console.log(`Found ${result.errorCount} errors and ${result.warningCount} warnings`);
console.log('Formatted output:');
console.log(result.output);
// Access individual failures
result.failures.forEach(failure => {
console.log(`${failure.getFileName()}:${failure.getStartPosition().line + 1} - ${failure.getFailure()}`);
});class Linter {
static VERSION: string = "6.1.3";
static findConfiguration: typeof Configuration.findConfiguration;
static findConfigurationPath: typeof Configuration.findConfigurationPath;
static getRulesDirectories: typeof Configuration.getRulesDirectories;
static loadConfigurationFromPath: typeof Configuration.loadConfigurationFromPath;
}static createProgram(configFile: string, projectDirectory?: string): ts.ProgramCreates a TypeScript program from a tsconfig.json file for type-aware linting.
Parameters:
configFile - Path to tsconfig.json fileprojectDirectory - Optional project root directoryExample:
// Create TypeScript program for type-aware rules
const program = Linter.createProgram('./tsconfig.json', './');
const linter = new Linter({ fix: false }, program);
// Lint files with type information
const fileNames = Linter.getFileNames(program);
fileNames.forEach(fileName => {
const sourceFile = program.getSourceFile(fileName);
if (sourceFile) {
linter.lint(fileName, sourceFile.getFullText(), configuration);
}
});static getFileNames(program: ts.Program): string[]Extracts lintable file names from a TypeScript program, excluding declaration files.
import { Configuration, IConfigurationLoadResult } from 'tslint';
// Find configuration relative to a file
const configResult: IConfigurationLoadResult = Configuration.findConfiguration(
'./tslint.json',
'./src/myfile.ts'
);
if (configResult.results) {
// Use the loaded configuration
linter.lint('myfile.ts', source, configResult.results);
}interface IConfigurationFile {
extends: string[];
jsRules: Map<string, Partial<IOptions>>;
linterOptions?: {
exclude: string[];
format: string;
};
rulesDirectory: string[];
rules: Map<string, Partial<IOptions>>;
}import { Linter, Configuration } from 'tslint';
import * as fs from 'fs';
import * as glob from 'glob';
function lintProject(pattern: string, configPath: string): LintResult {
const linter = new Linter({ fix: false, formatter: 'json' });
const config = Configuration.loadConfigurationFromPath(configPath);
const files = glob.sync(pattern);
files.forEach(filePath => {
const source = fs.readFileSync(filePath, 'utf8');
linter.lint(filePath, source, config.results);
});
return linter.getResult();
}
// Usage
const result = lintProject('./src/**/*.ts', './tslint.json');
console.log(`Project has ${result.errorCount} errors`);import { Linter, Configuration } from 'tslint';
import * as ts from 'typescript';
function lintWithTypeChecking(projectPath: string): LintResult {
// Create TypeScript program
const program = Linter.createProgram('./tsconfig.json', projectPath);
const linter = new Linter({ fix: false }, program);
// Load configuration
const config = Configuration.loadConfigurationFromPath('./tslint.json');
// Get files to lint
const fileNames = Linter.getFileNames(program);
fileNames.forEach(fileName => {
const sourceFile = program.getSourceFile(fileName);
if (sourceFile) {
linter.lint(fileName, sourceFile.getFullText(), config.results);
}
});
return linter.getResult();
}import { Linter, RuleFailure, Replacement } from 'tslint';
import * as fs from 'fs';
function lintAndFix(filePath: string, config: any): string {
const source = fs.readFileSync(filePath, 'utf8');
const linter = new Linter({ fix: true });
linter.lint(filePath, source, config);
const result = linter.getResult();
// Apply fixes to source code
if (result.fixes && result.fixes.length > 0) {
const fixes = result.fixes
.map(failure => failure.getFix())
.filter(fix => fix !== undefined) as Replacement[][];
const allReplacements = fixes.reduce((acc, fix) => acc.concat(fix), []);
return Replacement.applyAll(source, allReplacements);
}
return source;
}import { Linter, AbstractFormatter } from 'tslint';
class CustomFormatter extends AbstractFormatter {
public format(failures: RuleFailure[]): string {
return failures.map(failure =>
`⚠️ ${failure.getFileName()}: ${failure.getFailure()}`
).join('\n');
}
}
// Use custom formatter
const linter = new Linter({
fix: false,
formatter: CustomFormatter
});import { Linter, Configuration } from 'tslint';
function safeLint(fileName: string, source: string): LintResult | null {
try {
const linter = new Linter({ fix: false });
// Attempt to load configuration
let config;
try {
config = Configuration.findConfiguration('./tslint.json', fileName).results;
} catch (configError) {
console.warn('Configuration not found, using defaults');
config = undefined;
}
linter.lint(fileName, source, config);
return linter.getResult();
} catch (error) {
console.error('Linting failed:', error.message);
return null;
}
}// Efficient for linting multiple files with type checking
const program = Linter.createProgram('./tsconfig.json');
const linter = new Linter({ fix: false }, program);
// Reuse the same linter and program for multiple files
Linter.getFileNames(program).forEach(fileName => {
const sourceFile = program.getSourceFile(fileName);
if (sourceFile) {
linter.lint(fileName, sourceFile.getFullText(), config);
}
});// For large projects, process files in batches
function lintInBatches(files: string[], batchSize: number = 50): LintResult[] {
const results: LintResult[] = [];
for (let i = 0; i < files.length; i += batchSize) {
const batch = files.slice(i, i + batchSize);
const linter = new Linter({ fix: false });
batch.forEach(file => {
const source = fs.readFileSync(file, 'utf8');
linter.lint(file, source, config);
});
results.push(linter.getResult());
}
return results;
}import { Linter, Configuration } from 'tslint';
import * as express from 'express';
function createLintMiddleware() {
const config = Configuration.loadConfigurationFromPath('./tslint.json');
return (req: express.Request, res: express.Response, next: express.NextFunction) => {
if (req.body && req.body.source) {
const linter = new Linter({ fix: false, formatter: 'json' });
linter.lint('uploaded.ts', req.body.source, config.results);
req.lintResult = linter.getResult();
}
next();
};
}// Webpack plugin example
class TSLintPlugin {
apply(compiler: any) {
compiler.hooks.emit.tapAsync('TSLintPlugin', (compilation: any, callback: Function) => {
const linter = new Linter({ fix: false });
const config = Configuration.loadConfigurationFromPath('./tslint.json');
// Lint all TypeScript assets
Object.keys(compilation.assets).forEach(filename => {
if (filename.endsWith('.ts')) {
const source = compilation.assets[filename].source();
linter.lint(filename, source, config.results);
}
});
const result = linter.getResult();
if (result.errorCount > 0) {
compilation.errors.push(new Error('TSLint errors found'));
}
callback();
});
}
}Install with Tessl CLI
npx tessl i tessl/npm-tslint