This error occurs when you use a TypeScript ESLint rule that requires type information, but your ESLint configuration hasn't been set up to generate the necessary type services from your TypeScript compiler. The fix involves configuring parserOptions with either projectService or project to enable type-aware linting.
The "@typescript-eslint parser requires TypeScript service" error appears when you're using ESLint rules that need access to TypeScript's type checker (known as "typed linting"), but your ESLint configuration doesn't provide the necessary connection to your TypeScript project. Many powerful @typescript-eslint rules—like those that check for unused variables with type information, enforce strict null checks, or validate promise handling—require access to TypeScript's type system to work correctly. These rules need to understand not just the syntax of your code, but also the types of variables, function return types, and other type-level information. To provide this type information, the @typescript-eslint parser needs to know where your tsconfig.json file is located and how to use it. Without this configuration, the parser can only perform syntax-level checks, and any rule requiring type information will fail with this error. This is different from basic syntax errors—your TypeScript code may compile fine, but ESLint can't perform type-aware analysis because it doesn't know how to access TypeScript's compiler API for type checking.
The simplest way to fix this is to enable the projectService option in your ESLint configuration. This is the modern approach that automatically finds your tsconfig.json:
// .eslintrc.js or .eslintrc.cjs
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
};For ESLint flat config (eslint.config.js):
// eslint.config.js
import tseslint from '@typescript-eslint/eslint-plugin';
import parser from '@typescript-eslint/parser';
export default [
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: parser,
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
'@typescript-eslint': tseslint,
},
},
];After updating your config, restart your IDE and run ESLint again.
If you need more control or are using an older version of @typescript-eslint, specify the tsconfig.json path explicitly:
// .eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
extends: [
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
};For monorepos with multiple tsconfig files:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: [
'./tsconfig.json',
'./packages/*/tsconfig.json',
],
tsconfigRootDir: __dirname,
},
};Using project: true auto-discovers the nearest tsconfig.json:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
};ESLint can only analyze files that are part of your TypeScript project. Check that the files you're linting are included in tsconfig.json:
{
"include": [
"src/**/*",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules",
"dist",
"build"
]
}If you need to lint files outside your main TypeScript project (like config files), create a separate tsconfig.eslint.json:
// tsconfig.eslint.json
{
"extends": "./tsconfig.json",
"include": [
"src/**/*",
".eslintrc.js",
"*.config.ts",
"scripts/**/*"
]
}Then reference it in ESLint config:
module.exports = {
parserOptions: {
project: './tsconfig.eslint.json',
tsconfigRootDir: __dirname,
},
};If you have a mixed codebase with both TypeScript and JavaScript files, configure ESLint to only use type-aware rules on TypeScript files:
// .eslintrc.js
module.exports = {
overrides: [
{
// TypeScript files: enable type-aware linting
files: ['*.ts', '*.tsx'],
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
extends: [
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
},
{
// JavaScript files: disable type-aware rules
files: ['*.js', '*.jsx'],
extends: [
'plugin:@typescript-eslint/recommended',
],
},
],
};Or exclude config files from type checking:
module.exports = {
ignorePatterns: [
'*.config.js',
'.eslintrc.js',
'jest.config.js',
],
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
};Ensure you have the required packages installed:
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin
# Or with yarn
yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
# Or with pnpm
pnpm add -D @typescript-eslint/parser @typescript-eslint/eslint-pluginCheck that versions are compatible:
npm list @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript eslintAll @typescript-eslint packages should have the same major version:
{
"devDependencies": {
"@typescript-eslint/parser": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"typescript": "^5.0.0",
"eslint": "^8.0.0"
}
}If versions are mismatched, update them:
npm update @typescript-eslint/parser @typescript-eslint/eslint-pluginSometimes ESLint's cache gets stale after configuration changes:
# Clear ESLint cache
rm -rf .eslintcache
npx eslint . --cache --cache-location .eslintcache
# Or run without cache
npx eslint . --no-cacheIf using VS Code, restart the ESLint server:
1. Press Cmd/Ctrl + Shift + P
2. Type "ESLint: Restart ESLint Server"
3. Select the command
For other IDEs:
- WebStorm/IntelliJ: File → Invalidate Caches / Restart
- Sublime Text: Restart the editor
- Vim/Neovim: Restart your LSP client (:LspRestart or :CocRestart)
Then re-run ESLint:
npx eslint src/### Performance Considerations
Type-aware linting is significantly slower than syntax-only linting because it requires running TypeScript's full type checker. For large projects, this can take several seconds or even minutes.
Optimization strategies:
1. Use projectService instead of project with globs: The projectService: true option is more efficient than globbing multiple tsconfig files.
2. Limit which rules require type information: Not all rules need types. Review your rules and use type-aware rules only where necessary:
// Instead of extending all type-aware rules
extends: ['plugin:@typescript-eslint/recommended-requiring-type-checking'],
// Enable only specific type-aware rules you need
rules: {
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-misused-promises': 'error',
}3. Use allowDefaultProject for config files: If linting config files is slow, allow them to use default compiler options:
parserOptions: {
projectService: {
allowDefaultProject: ['*.config.ts', '.eslintrc.js'],
},
tsconfigRootDir: __dirname,
}### Understanding the Difference Between project and projectService
`project` (legacy approach):
- Requires explicit path(s) to tsconfig.json
- Supports glob patterns: ./packages/*/tsconfig.json
- You manage which tsconfig applies to which files
- Can be slower with many tsconfig files
`projectService` (modern approach, v6.0+):
- Automatically finds the nearest tsconfig.json for each file
- Simpler configuration, just set projectService: true
- Better performance for monorepos
- Recommended for new projects
### Monorepo Configuration
For monorepos using multiple packages:
// Root .eslintrc.js
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
},
};
// packages/app/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"include": ["src"]
}
// packages/lib/tsconfig.json
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"include": ["src"]
}The projectService will automatically use the correct tsconfig for each package.
### Migrating from Older Versions
If migrating from @typescript-eslint v5 or earlier:
Old config (v5):
parserOptions: {
project: './tsconfig.json',
}New config (v6+):
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
}The EXPERIMENTAL_useProjectService option from v5 is now projectService in v6+.
### CI/CD Optimization
For CI environments, type-aware linting can slow down your pipeline. Consider:
1. Run type-aware linting only on changed files:
# Using lint-staged
npx lint-staged2. Separate type checking from linting:
# Type check
npm run type-check # tsc --noEmit
# Lint (without type-aware rules)
npm run lint # eslint without type checking3. Cache ESLint results:
npx eslint . --cache --cache-location .eslintcacheAdd .eslintcache to your CI cache (GitHub Actions, GitLab CI, etc.) to reuse results across builds.
### Debugging Type Service Issues
If the error persists, debug what TypeScript files ESLint sees:
# Show which files TypeScript includes
npx tsc --listFiles | head -20
# Test ESLint on a single file
npx eslint --debug src/index.ts 2>&1 | grep -i "parser|project"Check if ESLint can find your tsconfig:
// Add to .eslintrc.js temporarily
console.log('tsconfig path:', require('path').resolve(__dirname, 'tsconfig.json'));Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript