Repository navigation
allow voluntary .ts suffix for import paths #37582
Description
Activity
- addedIn DiscussionNot yet reached consensusNot yet reached consensusSuggestionAn idea for TypeScriptAn idea for TypeScript
on Mar 27, 2020 After some more research I wonder if that behavior could even be more guided by a compiler option like
--noImplicitSuffix.
That would be in alignment with--noImplicitAnyand give the developer the choice, yet push for a valid, not "magical" resolved path if not set.What are your thoughts on that?
Reacted by Marvin Hagemeister, Farzad Senart, Dan Mercer, jdmichaud, Okku, Oliver, Dj, ljmsu, joker63, Reinis and 58 moreRead through the above and it seems to boil down to multiple build targets with different file extensions throws a wrench in things when supporting using the file extensions on imports. Where it diverges in my mind, and hopefully Jack Works (@Jack-Works) you can illuminate this a bit, is that we'd be importing .ts extensions which would have to be rewritten anyways.
Reacted by Daniel JohnsSo... where are we actually at with this?
Scattered issues / feature requests don't help, and the confusing (and somewhat untimely) response(s) from official TypeScript members haven't helped me understand how this feature will be implemented (it will have to be, eventually).
All I can ascertain is that this is has yet to be resolved.
Can someone explain in plain English when and how these multiple issues will be fixed, please?
Reacted by joker63, Tim Reichen, Jo, James.Li, Izel Nakri | izelnakri.eth, csha, Jacob Mischka, Maga D. Zandaqo, Tarjei Skjærset, A. Matías Quezada and 17 more- added 9 commits that reference this issue
on Jan 7, 2021 107 remaining items
I hope this also allows enforcing the use of extensions as an option so that imports without extensions aren't allowed
Reacted by Wenfang Du and mhanuszhandrewbranch commented
on Dec 14, 2022 MemberMore actionsIt does not. You might want to track #50153, and if you’re concerned with Deno, see my advice at #51669 (comment).
enforcing the use of extensions as an option so that imports without extensions aren't allowed
To approach this problem from another angle, you may want to consider
eslint-plugin-nodewith thenode/file-extension-in-importoption:This is what we've been using to enforce
.jsextensions in our TypeScript code (because we're using ESM with Node.js, which requires the extensions). Haven't tried it yet with.tsextensions.Reacted by Raul Macarieandrewbranch commented
on Dec 14, 2022 MemberMore actionsIf you are compiling TS code to JS code that will run in Node, you should be using
--module nodenext(which implies--moduleResolution nodenext), which requires extensions in precisely the places that Node does. No lint rule should be necessary if your reason for enforcing extensions is that you want your code to run in Node. That is built into TypeScript, and has been for about a year. #51669 is made for bundlers, and there is not a single bundler I know of (and I tested a bunch) that ever requires extensions on imports, so likewise it is not a requirement of the module resolution mode.Reacted by Jordan Harband and Lee GoddardJust saw #51669–is this really finally fixed?!
Reacted by DeedleFakeNo lint rule should be necessary if your reason for enforcing extensions is that you want your code to run in Node. That is built into TypeScript, and has been for about a year.
We added this lint rule because we had breakages that we would only see in the production builds (because use
tsmandesbuildfor dev mode, which does not have a problem with lacking extensions).The inconsistencies between bundlers allowing no extensions and
.tsextensions and TypeScript allowing for module resolution to other file extensions like.tsxhave been a bit of a headache to say the least, lots of hours spent on this in the ecosystem:- webpack Inconsistency with TypeScript in Module Resolution with Fully-Specified ESM Imports webpack/webpack#13252
- tsm Resolve .tsx files from .js extensions lukeed/tsm#33
- tsx Resolve .tsx + other extensions when importing .js / .jsx files privatenumber/tsx#112
- Next.js Module not found: Fully Specified ESM Imports (with
.jsextension) in TypeScript vercel/next.js#41961
Ideal feels like TS should just allow for
.ts/.tsx/ etc extensions as well and just transpile those import paths to whatever the final file extension will be, as an exception of the rule "TypeScript doesn't modify JavaScript code you write"It seems almost like maybe that's what
--moduleResolution bundler+allowImportingTsExtensionsis? But it doesn't seem to be able to emit like this, which would also be desirable.But indeed, TypeScript does show the error about missing file extensions also in the IDE, which is great - thanks for the tip! I needed to do some configuration for this, but it's working.
I'll try applying it to those projects, maybe they are just not configured the same way.
- Repo: https://github.com/karlhorky/typescript-esm-fully-specified-extensions
- Demo (StackBlitz): https://stackblitz.com/github/karlhorky/typescript-esm-fully-specified-extensions?file=index.ts
I needed to add
"type": "module"to mypackage.jsonas well as a few things to mytsconfig.json:{ "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext"], "module": "NodeNext", "target": "ESNext", "moduleResolution": "NodeNext", "resolveJsonModule": true, "esModuleInterop": true, "isolatedModules": true, "allowJs": true, "downlevelIteration": true, "forceConsistentCasingInFileNames": true, "noEmit": true, "noFallthroughCasesInSwitch": true, "skipLibCheck": true, "strict": true, "incremental": true, "noUncheckedIndexedAccess": true }, "include": [ "**/.eslintrc.cjs", "next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.cjs", "**/*.mjs" ], "exclude": ["node_modules", "build"] }andrewbranch commented
on Dec 15, 2022 MemberMore actionsI needed to add
"type": "module"to mypackage.jsonYes, because without either this or
.mts/.mjsextensions, you do not have ES modules at all. Node supports both ESM and CJS files, and CJS files are allowed to write module specifiers without extensions. All your.tsfiles are CJS modules until you add"type": "module". (There will also be a new flag in 5.0 that prevents you from writing ESM syntax in CJS modules, since that is probably a major source of confusion: #51479.)as well as a few things to my
tsconfig.jsonThis rule is only relevant in
node16/nodenextbecause that’s the only mode that targets versions of Node that have ESM support. The mode callednodeis out of date and is being renamed tonode10: #51901.Andrew Branch (@andrewbranch) it would be really great if TS made it easy to use native ESM without type module, since that package.json flag causes lots of issues with outdated tooling and also causes lots of confusion for new users.
andrewbranch commented
on Dec 15, 2022 MemberMore actionsJordan Harband (@ljharb) can you expound on that? In modes made for Node, we’re just doing what Node requires (assuming it’s invoked with no special CLI flags altering the behavior) as far as I know. If we were to emit a
.jsfile with ESM syntax, users would get this:image text
// a.js import path from "path"; ❯ node --version v16.17.1 ❯ node a.js (node:8214) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. (Use `node --trace-warnings ...` to show where the warning was created) /Users/andrew/Developer/microsoft/eg/js/a.js:1 import path from "path"; ^^^^^^ SyntaxError: Cannot use import statement outside a module at Object.compileFunction (node:vm:360:18) at wrapSafe (node:internal/modules/cjs/loader:1055:15) at Module._compile (node:internal/modules/cjs/loader:1090:27) at Object.Module._extensions..js (node:internal/modules/cjs/loader:1180:10) at Module.load (node:internal/modules/cjs/loader:1004:32) at Function.Module._load (node:internal/modules/cjs/loader:839:12) at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12) at node:internal/main/run_main_module:17:47Andrew Branch (@andrewbranch) right - i'm asking for there to be a way to emit
.mjsfiles instead (or.cjs, if it's CJS, i suppose).Reacted by Offirmoandrewbranch commented
on Dec 15, 2022 MemberMore actionsThere is, just name your files
.mtsor.ctsah, ok great thanks :-)
Reacted by Andrew BranchSee the following
tsconfig.json:{ "compilerOptions": { "moduleResolution": "bundler", "allowImportingTsExtensions": true } }
Reacted by Michael J. Ryan, Sina Khodabandehloo and Donovan Glover- added a commit that references this issue
on Apr 16, 2026


Search Terms
.ts
suffix
imports
extension
Suggestion
Typescript doesn't recognize file imports with
.tssuffix.Allow voluntary
.tsto be added to import paths.Use Cases
It seems right to be able to use a correct path to a file without magic resolution.
This would help to align with deno which uses mandatory suffixes o files.
Examples
let
import a from "path/to/a.ts"behave the same as
import a from "path/to/a"Checklist
My suggestion meets these guidelines: