TSSLint is probably the smallest linter implementation ever. Built on the TypeScript Language Server (tsserver), it provides a minimalist diagnostic extension interface with zero default rules, allowing developers to implement custom rules with minimal overhead.
TSSLint is the spiritual successor to TSLint. We believe that direct integration with native TypeScript APIs is the most efficient way to lint TypeScript code.
General-purpose linters like ESLint, while powerful, operate as separate processes and often need to re-initialize type-checking context. This leads to a significant pain point in large-scale projects: editor lag during "Auto Fix on Save".
TSSLint solves this by running directly as a tsserver plugin. By sharing the existing TypeChecker and operating on the native TypeScript AST (without ESTree/ES parser conversion), TSSLint provides near-instant diagnostics and fixes.
- Project-Centric: Treats the Project (tsconfig) as a first-class citizen, enabling efficient cross-file type analysis and superior Monorepo support.
- High Performance: Runs as a
tsserverplugin, sharing the existingTypeCheckerto provide near-instant diagnostics without redundant parsing. - Minimalist Implementation: Probably the smallest linter ever. Zero built-in rules and minimal code overhead by leveraging native TypeScript infrastructure.
- Rule Traceability: Built-in debugging support. Jump from a reported error directly to the exact line in your rule's source code that triggered it.
TSSLint integrates into tsserver via the TypeScript plugin system, leveraging the semantic information already computed by your editor. Operating at the project level ensures accurate and performant diagnostics.
Since TSSLint operates directly within tsserver, it supports any framework that integrates with the TypeScript plugin system.
Tools like Vue Official (Volar), MDX, or Astro virtualize non-TypeScript files into virtual TypeScript source files for tsserver. TSSLint seamlessly accesses and lints the TypeScript code within these virtual files without any additional configuration.
npm install @tsslint/config --save-devA minimal configuration looks like this. For a complete example, see the vuejs/language-tools tsslint.config.ts.
import { defineConfig } from '@tsslint/config';
export default defineConfig({
rules: {
// Define or import your rules here
},
});- VSCode:
- Install the TSSLint extension.
- (Optional) If you encounter issues importing
tsslint.config.tsdue to Node.js version mismatches, you can configuretypescript.tsserver.nodePathto point to a Node.js 23.6.0+ executable.
- Other Editors: Configure TSSLint as a plugin in your
tsconfig.json:{ "compilerOptions": { "plugins": [{ "name": "@tsslint/typescript-plugin" }] } }
// rules/no-debugger.ts
import { defineRule } from '@tsslint/config';
export default defineRule(({ typescript: ts, file, report }) => {
ts.forEachChild(file, function cb(node) {
if (node.kind === ts.SyntaxKind.DebuggerStatement) {
report(
'Debugger statement is not allowed.',
node.getStart(file),
node.getEnd()
);
}
ts.forEachChild(node, cb);
});
});TSSLint's high performance comes from its intelligent caching strategy, which automatically distinguishes between Syntax-Aware and Type-Aware rules.
All rule diagnostics are cached by default. The cache is automatically disabled for a rule in two scenarios:
- Type-Aware Detection: If a rule accesses
RuleContext.program(e.g., to check types), TSSLint detects it as Type-Aware. The cache for this rule is then automatically managed and invalidated to ensure accuracy. - Manual Exclusion: A rule can explicitly prevent a specific diagnostic from being cached by calling
report().withoutCache().
This automatic differentiation maximizes performance for simple syntax rules while maintaining correctness for complex type-aware rules.
TSSLint is designed to make rule debugging trivial. Every time you call report(), TSSLint automatically captures the current JavaScript stack trace and attaches it to the diagnostic as Related Information.
This means: You can click on the diagnostic in your editor and jump directly to the line in your rule's source code that triggered the report.
The .at() method is generally not needed, but is provided for advanced scenarios where you wrap report() in a helper function and need to adjust the stack depth to point to the correct logic:
// Example of advanced usage to adjust stack depth
report('message', start, end)
.at(new Error(), 2) // Adjusts the stack index to skip the helper function's frame
.withFix(...);The @tsslint/cli package provides a command-line tool for CI/CD and build processes.
# Lint a project
npx tsslint --project path/to/tsconfig.json
# Auto-fix violations
npx tsslint --project path/to/tsconfig.json --fix
# Lint multiple projects
npx tsslint --project packages/*/tsconfig.json --vue-project apps/web/tsconfig.json
# Using brace expansion for multiple patterns
npx tsslint --project {tsconfig.json,packages/*/tsconfig.json,extensions/*/tsconfig.json}Tip
TSSLint focuses on diagnostic fixes and does not include a built-in formatter. It is recommended to run a dedicated formatter like Prettier, dprint, or oxfmt after running TSSLint with --fix.
import { defineConfig, createIgnorePlugin } from '@tsslint/config';
export default defineConfig({
rules: {
...
},
plugins: [
createIgnorePlugin('tsslint-ignore', true)
],
});Usage: Use // tsslint-ignore comments in your code.
TSSLint provides compatibility layers for existing linter ecosystems. The integration functions are available via @tsslint/config, and you only need to install the original linter package to use them.
npm install [email protected] @typescript-eslint/parser --save-devimport { defineConfig, importESLintRules } from '@tsslint/config';
export default defineConfig({
rules: {
...await importESLintRules({
'no-unused-vars': true,
'@typescript-eslint/no-explicit-any': true,
}),
},
});importESLintRules will automatically resolve and load rules from ESLint plugins (e.g., @typescript-eslint/eslint-plugin) by searching your node_modules. Plugin rules are identified by their prefix (e.g., @typescript-eslint/).
npm install tslint --save-devimport { defineConfig, importTSLintRules } from '@tsslint/config';
export default defineConfig({
rules: {
...await importTSLintRules({
'no-console': true,
'member-ordering': [true, { order: 'fields-first' }],
}),
},
});importTSLintRules will automatically read rulesDirectory from your tslint.json to support third-party TSLint plugins.
npm install tsl --save-devimport { defineConfig, fromTSLRules } from '@tsslint/config';
import { core } from 'tsl';
export default defineConfig({
rules: fromTSLRules(core.all()),
});- Node.js: Requires 22.6.0+ (v3.0+).
- TypeScript: Incompatible with
typescript-go(v7) as it does not support Language Service Plugins.



