Node.js
Typescript eslint - Missing file extension ts importextensions
Navigating the intricacies of modern JavaScript development often means wrestling with tooling, and few tools are as essential yet occasionally perplexing as ESLint, especially when paired with TypeScript. Developers frequently encounter the “Typescript eslint - Missing file extension ’ts’ import/extensions” error, a seemingly minor issue that can halt progress and clutter your console. This particular warning or error arises when ESLint, specifically the import/extensions rule from eslint-plugin-import, expects explicit file extensions on your module imports, which is often at odds with how TypeScript and module bundlers typically handle resolution. Understanding the root cause and implementing the correct fixes is crucial for maintaining a clean codebase and an efficient development workflow.
Understanding the import/extensions Rule
The import/extensions rule is part of the popular eslint-plugin-import, a plugin designed to lint ES2015+ import/export syntax and prevent issues with misspelling of file paths and other import-related problems. Its primary purpose is to ensure consistency in how modules are imported across a project. By default, this rule often expects that all import paths, even for local files, include their respective file extensions. For instance, instead of import { SomeModule } from './SomeModule';, it might demand import { SomeModule } from './SomeModule.js'; or ./SomeModule.ts.
This rule becomes particularly challenging in a TypeScript environment because TypeScript’s module resolution system, coupled with bundlers like Webpack or Rollup, is designed to resolve imports without explicit extensions. When you write import { fetchData } from './utils/api';, TypeScript and your bundler automatically look for ./utils/api.ts, ./utils/api.tsx, ./utils/api/index.ts, and so on. This implicit resolution is a convenience that significantly streamlines development. However, ESLint’s import/extensions rule, when not properly configured, clashes with this behavior, leading to the “missing file extension ’ts’” error.
The conflict often stems from the transition complexities between CommonJS (CJS) and ES Modules (ESM) in Node.js environments. While ESM explicitly requires file extensions, TypeScript’s compiler options like "moduleResolution": "node" mimic Node.js’s CJS resolution, which allows omitting extensions. This discrepancy creates friction when linting tools try to enforce ESM-like strictness on a codebase that leverages TypeScript’s more flexible resolution. As noted by the Node.js documentation, explicit extensions are a key differentiator for ES Modules, reinforcing why linting tools might push for this behavior even in TypeScript projects. Read more about Node.js ES Modules.
Why This Error Occurs: The Root Causes
The “Typescript eslint - Missing file extension ’ts’ import/extensions” error primarily stems from a mismatch between your ESLint configuration and how TypeScript or your module bundler handles module resolution. TypeScript’s compiler, by default, is highly capable of resolving imports without explicit file extensions, especially when "moduleResolution" is set to "node" in your tsconfig.json. This setting tells TypeScript to emulate Node.js’s resolution algorithm, which searches for files with common extensions (like .ts, .tsx, .d.ts, .js, .jsx) and also looks for index.ts files within directories.
The eslint-plugin-import, however, often adheres to a stricter interpretation, particularly aiming to align with the future of ES Modules where explicit file extensions are mandatory. When this plugin’s import/extensions rule is enabled and not properly configured for TypeScript projects, it flags every import statement missing a .ts (or other configured) extension. This is because ESLint, without specific instructions, doesn’t inherently understand TypeScript’s module resolution capabilities or the nuances of how bundlers transform and resolve these paths.
Another contributing factor is the evolving landscape of module systems. Historically, CommonJS (CJS) modules in Node.js did not require file extensions for imports, while ES Modules (ESM) do. TypeScript projects can be compiled to either CJS or ESM, and the linting rules often struggle to adapt to the chosen target without explicit configuration. For example, if your project targets ESM, ESLint might enforce .js extensions (as TypeScript compiles .ts to .js), even though you’re writing .ts files. This often means that your ESLint setup isn’t correctly differentiating between source file extensions and the eventual compiled output extensions, leading to the “missing file extension ’ts’” message even when the intent is to compile to .js.
In essence, the error is a configuration gap. ESLint is trying to enforce a rule that doesn’t align with TypeScript’s default module resolution logic or your project’s chosen compilation target. Bridging this gap requires careful adjustments to your .eslintrc configuration, specifically targeting the import/extensions rule and instructing it how to behave within a TypeScript context. For a deeper dive into TypeScript’s compiler options, consult the official TypeScript documentation on tsconfig.json.
Resolving the Missing file extension 'ts' Error
To effectively resolve the “Typescript eslint - Missing file extension ’ts’ import/extensions” error, you need to configure ESLint to understand TypeScript’s module resolution. The most common and recommended approach involves adjusting the import/extensions rule within your .eslintrc file. This allows you to tell ESLint which extensions it should expect or, more practically for TypeScript, which extensions it should ignore when performing its checks.
One effective strategy is to instruct the import/extensions rule to ignore .ts and .tsx files, as TypeScript handles Question & Answer :
I have a simple Node/Express app made with Typescript. And eslint give me the error
Missing file extension "ts" for "./lib/env" import/extensions
Here is my .eslintrc file
{ "extends": [ "airbnb", "plugin:@typescript-eslint/recommended", "prettier", "prettier/react", "plugin:import/errors", "plugin:import/warnings", "plugin:import/typescript" ], "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint", "prettier", "import"], "settings": { "import/extensions": [".js", ".jsx", ".ts", ".tsx"], "import/parsers": { "@typescript-eslint/parser": [".ts", ".tsx"] }, "import/resolver": { "typescript": { "directory": "./tsconfig.json" }, "node": { "extensions": [".js", ".jsx", ".ts", ".tsx"] } } }, "rules": { "@typescript-eslint/indent": [2, 2], "no-console": "off", "import/no-unresolved": [2, { "commonjs": true, "amd": true }], "import/named": 2, "import/namespace": 2, "import/default": 2, "import/export": 2 } }
I have installed eslint-plugin-import & eslint-import-resolver-typescript. And I cannot figure out why, I got that error.
Add the following code to rules:
"rules": { "import/extensions": [ "error", "ignorePackages", { "js": "never", "jsx": "never", "ts": "never", "tsx": "never" } ] }
airbnb ESLint config leads the problem.