This error occurs when @typescript-eslint/parser cannot locate or initialize the TypeScript language service, typically due to misconfigured parserOptions.project settings, missing tsconfig.json files, or files not included in your TypeScript project configuration. The fix usually involves correctly configuring the project path or updating your tsconfig.json include patterns.
The "Cannot resolve TypeScript service" error appears when ESLint's TypeScript parser (@typescript-eslint/parser) fails to initialize the TypeScript language service for type-aware linting. This parser relies on TypeScript's Program API to provide type information for advanced lint rules, but it can only work when properly connected to a valid tsconfig.json file. This error is specific to "typed linting" - the feature that enables ESLint rules requiring type information, such as @typescript-eslint/no-floating-promises, @typescript-eslint/no-unnecessary-type-assertion, and similar rules that need to understand your code's type system. Common scenarios where this error appears: 1. **Missing or misconfigured parserOptions.project**: The ESLint config doesn't point to a valid tsconfig.json file 2. **Files outside project scope**: You're linting files that aren't included in your tsconfig.json's "include" array 3. **Incorrect working directory**: ESLint is running from a different directory than expected, breaking relative path resolution 4. **Project structure mismatches**: Monorepos or multi-project setups where different directories need different TypeScript configurations
The most common fix is to properly configure the project option in your ESLint config to point to your tsconfig.json:
For .eslintrc.js:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint'],
extends: [
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
],
};For eslint.config.js (flat config):
import tseslint from '@typescript-eslint/eslint-plugin';
import parser from '@typescript-eslint/parser';
export default [
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: parser,
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: import.meta.dirname,
},
},
plugins: { '@typescript-eslint': tseslint },
},
];Key points:
- Use tsconfigRootDir: __dirname to ensure paths resolve correctly regardless of where ESLint runs
- The project path should be relative to tsconfigRootDir
- For multiple tsconfig files, use an array: project: ['./tsconfig.json', './tsconfig.node.json']
As of @typescript-eslint v5.52.0+, you can set project: true to automatically find the nearest tsconfig.json for each file:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
};This approach:
- Automatically finds the closest tsconfig.json for each linted file
- Works well with monorepos where different packages have different configs
- Eliminates the need to manually specify multiple tsconfig paths
- Requires @typescript-eslint/parser v5.52.0 or newer
Example project structure:
my-project/
├── .eslintrc.js (with project: true)
├── tsconfig.json
├── packages/
│ ├── app/
│ │ └── tsconfig.json
│ └── lib/
│ └── tsconfig.jsonEach package's files will use their nearest tsconfig.json automatically.
Config files like .eslintrc.js, jest.config.ts, and other root-level TypeScript files often aren't included in your main tsconfig.json. Create a separate config for ESLint:
Create tsconfig.eslint.json:
{
"extends": "./tsconfig.json",
"include": [
"src/**/*",
".eslintrc.js",
"jest.config.ts",
"*.config.ts",
"scripts/**/*"
]
}Update .eslintrc.js to use it:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.eslint.json',
tsconfigRootDir: __dirname,
},
};Important notes:
- Don't name it tsconfig.json - the TypeScript service won't recognize other names
- Use extends to inherit your main compiler options
- Include all files you want to lint
- This config is only for linting, not compilation
If you're getting errors about specific files not being in your TypeScript project, add them to the include array:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true
},
"include": [
"src/**/*",
"tests/**/*",
"*.config.ts",
".eslintrc.ts"
],
"exclude": [
"node_modules",
"dist"
]
}Alternative: Use .eslintignore for files you don't want to lint:
Create .eslintignore in your project root:
# Don't lint config files
*.config.js
.eslintrc.js
# Don't lint build output
dist/
build/
# Don't lint dependencies
node_modules/This prevents ESLint from trying to lint files that shouldn't be type-checked.
If you upgraded to @typescript-eslint v6 and see module resolution errors, update your tsconfig.json moduleResolution strategy:
Old configuration (Node.js <16):
{
"compilerOptions": {
"moduleResolution": "node"
}
}New configuration (Node.js 16+):
{
"compilerOptions": {
"moduleResolution": "bundler",
// OR for Node.js projects:
"moduleResolution": "node16",
// OR:
"moduleResolution": "nodenext"
}
}Why this is needed:
@typescript-eslint v6+ uses package.json exports which require:
- Node.js 16 or higher
- Modern module resolution strategy (bundler, node16, or nodenext)
If you must stay on Node.js <16:
Downgrade to @typescript-eslint v5:
npm install --save-dev @typescript-eslint/parser@5 @typescript-eslint/eslint-plugin@5@typescript-eslint/parser requires TypeScript as a peer dependency:
# Check if TypeScript is installed
npm list typescript
# If missing, install it
npm install --save-dev typescript
# Verify version (should be 4.x or 5.x)
npx tsc --versionVersion compatibility:
| @typescript-eslint | TypeScript Version |
|--------------------|-------------------|
| v6.x | 4.3.5 - 5.3.x |
| v5.x | 3.3.1 - 5.1.x |
| v7.x | 4.7.4 - 5.4.x |
If you have multiple TypeScript versions (e.g., global + local), ensure ESLint uses the local one:
# Remove global TypeScript
npm uninstall -g typescript
# Use local TypeScript only
npx tsc --versionAfter making configuration changes, VS Code's ESLint server may have stale information:
Method 1: Command Palette
1. Press Cmd/Ctrl + Shift + P
2. Type "ESLint: Restart ESLint Server"
3. Press Enter
Method 2: Reload VS Code
1. Press Cmd/Ctrl + Shift + P
2. Type "Developer: Reload Window"
3. Press Enter
Method 3: Check ESLint Output
1. Open Output panel: View → Output
2. Select "ESLint" from dropdown
3. Look for error messages showing what went wrong
If errors persist:
Clear VS Code's cache and restart:
# Close VS Code completely
# Then on macOS/Linux:
rm -rf ~/.vscode/extensions/dbaeumer.vscode-eslint-*/
# On Windows:
# Delete: %USERPROFILE%\.vscode\extensions\dbaeumer.vscode-eslint-*
# Restart VS Code and reinstall ESLint extension### Monorepo and Multi-Project Setup
For complex project structures with multiple tsconfig.json files, use project references:
Root tsconfig.json:
{
"files": [],
"references": [
{ "path": "./packages/app" },
{ "path": "./packages/lib" }
]
}packages/app/tsconfig.json:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outDir": "./dist"
},
"include": ["src/**/*"],
"references": [
{ "path": "../lib" }
]
}ESLint config for monorepo:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
project: true, // Automatically finds nearest tsconfig.json
tsconfigRootDir: __dirname,
},
};### Performance Optimization for Large Projects
Type-aware linting can be slow on large codebases. Optimize with:
1. Selective type-aware rules:
module.exports = {
overrides: [
{
// Type-aware rules only for source files
files: ['src/**/*.ts', 'src/**/*.tsx'],
parserOptions: {
project: './tsconfig.json',
},
extends: ['plugin:@typescript-eslint/recommended-requiring-type-checking'],
},
{
// Faster rules for tests/config
files: ['tests/**/*.ts', '*.config.ts'],
extends: ['plugin:@typescript-eslint/recommended'],
},
],
};2. Use createProjectService (experimental):
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
projectService: {
allowDefaultProject: ['.eslintrc.js'],
defaultProject: './tsconfig.json',
},
tsconfigRootDir: __dirname,
},
};This uses TypeScript's language server for better performance.
### Debugging TypeScript Service Resolution
Use the --debug flag to see detailed resolution information:
# Enable ESLint debug output
DEBUG=eslint:* npx eslint src/
# Or just TypeScript parser debug
DEBUG=typescript-eslint:* npx eslint src/Check which tsconfig.json is being used:
npx eslint --print-config src/index.ts | grep -A 10 parserOptions### Common pitfalls
1. Relative paths without tsconfigRootDir:
// BAD - breaks when running ESLint from parent directory
parserOptions: {
project: './tsconfig.json',
}
// GOOD - always resolves correctly
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
}2. Using typed rules without project:
// BAD - rules require type info but project not configured
extends: ['plugin:@typescript-eslint/recommended-requiring-type-checking'],
parserOptions: {
// Missing: project option
}
// GOOD - project configured for typed rules
extends: ['plugin:@typescript-eslint/recommended-requiring-type-checking'],
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
}3. Linting files outside TypeScript project:
Files like .eslintrc.js, jest.config.js are often in project root but not in src/. Either:
- Add them to tsconfig.json include
- Create tsconfig.eslint.json that includes them
- Add them to .eslintignore if they don't need linting
### Alternative: Disable Type-Aware Linting
If you don't need type-aware rules, remove the project option entirely:
module.exports = {
parser: '@typescript-eslint/parser',
// No parserOptions.project
extends: ['plugin:@typescript-eslint/recommended'], // Non-typed rules only
};This makes ESLint much faster but disables rules requiring type information.
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