You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
rewriteRelativeImportExtensions: tsc doesn't rewrite extensions in emitted declaration files #61037
This is the behavior in every version I tried (even in the next 5.8.0), and I reviewed the FAQ for entries about "rewriteRelativeImportExtensions"
⏯ Playground Link
No response
💻 Code
In an index.ts file:
export*from'./file.ts';
then build it with tsc and "rewriteRelativeImportExtensions": true & "declaration": true in the compilerOptions of your tsconfig.json
🙁 Actual behavior
Built files content:
In the JS file, index.js, the extension is rewritten to .js:
export*from'./file.js';
In the declaration file, index.d.ts, the extension is not rewritten to .js:
export*from'./file.ts';
🙂 Expected behavior
In the declaration file, the extension should be rewritten to .js too:
export*from'./file.js';
Additional information about the issue
It occurs in the current TS 5.7.3 and in the next version (5.8.0-dev.20250123 at this time). Even if TS correctly interprets .d.ts files with .ts extensions in import/export, it's not the case of the IDE I use, PhpStorm. It can't provide a real code assistance with these declaration files.
In fact, I don't really know if it's a feature, a bug or an oversight in tsc, or if rewriteRelativeImportExtensions is just too new to be completely supported by all IDEs! Let me know!
Reading the Ryan Cavanaugh's comment and the rest of this thread let me think it's not really intentional but a form of "it's OK for TS, so there's no real problem with that". He only says what is clearly and intentionally not supported is the aliases resolving and rewriting, but it's not the problem here.
The fact is it breaks usages in some, maybe any, IDEs and probably in other tools, making this feature not totally usable in production right now. Maybe they will support it at some point, maybe not. I just think it's unfortunate in this case because if tsc is able to rewrite extensions in generated .js files, the gap to apply this to generated .d.ts files doesn't seem to be really high, while it ensures the best compatibility with existing tools in the eco-system.
I can't find any tests about this behavior in the linked PR, and the documentation doesn't mention it at all, it just says "output files", not "output files, excluding declaration files":
Rewrite .ts, .tsx, .mts, and .cts file extensions in relative import paths to their JavaScript equivalent in output files.
I really think generated .d.ts files were simply forgotten by this feature.
The usage problem that I encountered is precisely the one mentioned here : #59767 (comment). What this comment doesn't say, is it occurs in PhpStorm/WebStorm. I don't know for other IDEs or tools, I can only presume that the support is uneven, but at least Jetbrains IDEs fail to resolve relative imports in .d.ts files if the used extension is .ts, breaking the coding assistance on any exported thing in libraries where this appears. Typescript has no problem with that, as you stated yourself, it's perfectly valid for it. To be totally transparent, an issue in opened in Jetbrains Youtrack for more than a year, with no responses (see: https://youtrack.jetbrains.com/issue/WEB-64117/Ignore-file-extension-when-resolving-imports).
So what the problem behind that? It's really simple: finding public libraries with .d.ts having imports of *.ts is pretty uncommon at this time. In fact, I use, try and play with many typed libraries for a long time, and I've never spotted this Jetbrains issue before.
The first time I encountered it, is by experimenting the new rewriteRelativeImportExtensions tsc option in one of our internal library. I was evaluating the possibility to replace the tsx loader by the node native TS support, that requires to use source paths in imports rather than the traditional build destination paths required by TS (in fact, by the built ESM files as TS nearly ignores extensions). Currently, we use tsc to build our libraries, and we use tsx to comfortably launch units tests while developing, avoiding the need to build the library again and again, but also to run in place some TS scripts (some for development, some others distributed once built with tsc, some both). We clearly are in a situation where we run TS files in place and where we build a distributed ESM library on a single code base.
Since the introduction of the rewriteRelativeImportExtensions tsc option and my personal tests, I'm worried about the fact that these kind of .d.ts will be more and more common, in particular in public libraries published in npm repository, because this option will be used, and probably massively used, regardless of the doubts you raised for years about path rewriting (and to be really honest, I share these doubts) as there's few alternatives at this time to get a TS code base compatible with the more and more prominent "run TS in place" and building+distributing npm ESM modules.
That's why I said that rewriteRelativeImportExtensions is not reasonably usable in production right now: it may generate .d.ts files not totally compatible with the ecosystem (but perfectly valid in the TS point of view), at least not totally identical to those generated without this option + a traditional (with .js imports) ESM code base.
So Ryan, as you are one the deciders of the Typescript team, if tsc doesn't rewrite paths in .d.ts files, while it does rewrite the exact same ones in .js files, is it:
an oversight while implementing rewriteRelativeImportExtensions?
a bug?
a wanted behavior?
Even if my opinion is the first choice, it's just an opinion, not a definitive response. And I need a response, not an opinion, to continue my evaluations 🙂
If you want to update your build to add ESM support, which is generally why you’d be using this so that you can have imports with extensions, then your build will produce declaration files that look like this:
import foo from "./foo.ts"
There will be a file "./foo.d.ts" but no "./foo.ts"
This isn’t necessarily backwards compatible, but it easily could be if you were to just rewrite the extensions for the declaration files as well.
Reacted by Rob Knight, Nicolas ROGER and Steven Vachon
I hit this case while removing ts-node from the devDependencies of a project published to npmjs.
It's published to npm, so it must be compiled to .js and .d.ts files. Node will not resolve .ts files in node_modules, something TypeScript's developers seem in favor of nodejs/node#58429.
But it's useful to run development tests and scripts thru node's native typescript support, which requires .ts extensions.
Compiling for npm requires type stripping rewriting extensions.
tsc --rewriteRelativeImportExtensions produces working .js files, but the .d.ts files reference .ts files which caused typescript errors in consumers of my library.
node_modules/my-pkg/dist/index.d.ts(1,15): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './lib' instead.
Activity
MartinJohns commentedon Jan 24, 2025
This seems to be intentional, or at least not considered a bug: #59767 (comment)
darksabrefr commentedon Jan 24, 2025
Reading the Ryan Cavanaugh's comment and the rest of this thread let me think it's not really intentional but a form of "it's OK for TS, so there's no real problem with that". He only says what is clearly and intentionally not supported is the aliases resolving and rewriting, but it's not the problem here.
The fact is it breaks usages in some, maybe any, IDEs and probably in other tools, making this feature not totally usable in production right now. Maybe they will support it at some point, maybe not. I just think it's unfortunate in this case because if tsc is able to rewrite extensions in generated .js files, the gap to apply this to generated .d.ts files doesn't seem to be really high, while it ensures the best compatibility with existing tools in the eco-system.
I can't find any tests about this behavior in the linked PR, and the documentation doesn't mention it at all, it just says "output files", not "output files, excluding declaration files":
I really think generated .d.ts files were simply forgotten by this feature.
RyanCavanaugh commentedon Jan 24, 2025
Can you clarify what usages in particular? This isn't very concrete and there's no way for me to verify what you're referencing.
darksabrefr commentedon Jan 25, 2025
The usage problem that I encountered is precisely the one mentioned here : #59767 (comment). What this comment doesn't say, is it occurs in PhpStorm/WebStorm. I don't know for other IDEs or tools, I can only presume that the support is uneven, but at least Jetbrains IDEs fail to resolve relative
imports in.d.tsfiles if the used extension is.ts, breaking the coding assistance on any exported thing in libraries where this appears. Typescript has no problem with that, as you stated yourself, it's perfectly valid for it. To be totally transparent, an issue in opened in Jetbrains Youtrack for more than a year, with no responses (see: https://youtrack.jetbrains.com/issue/WEB-64117/Ignore-file-extension-when-resolving-imports).So what the problem behind that? It's really simple: finding public libraries with
.d.tshavingimports of*.tsis pretty uncommon at this time. In fact, I use, try and play with many typed libraries for a long time, and I've never spotted this Jetbrains issue before.The first time I encountered it, is by experimenting the new
rewriteRelativeImportExtensionstsc option in one of our internal library. I was evaluating the possibility to replace thetsxloader by the node native TS support, that requires to use source paths inimports rather than the traditional build destination paths required by TS (in fact, by the built ESM files as TS nearly ignores extensions). Currently, we usetscto build our libraries, and we usetsxto comfortably launch units tests while developing, avoiding the need to build the library again and again, but also to run in place some TS scripts (some for development, some others distributed once built withtsc, some both). We clearly are in a situation where we run TS files in place and where we build a distributed ESM library on a single code base.Since the introduction of the
rewriteRelativeImportExtensionstsc option and my personal tests, I'm worried about the fact that these kind of.d.tswill be more and more common, in particular in public libraries published in npm repository, because this option will be used, and probably massively used, regardless of the doubts you raised for years about path rewriting (and to be really honest, I share these doubts) as there's few alternatives at this time to get a TS code base compatible with the more and more prominent "run TS in place" and building+distributing npm ESM modules.That's why I said that
rewriteRelativeImportExtensionsis not reasonably usable in production right now: it may generate.d.tsfiles not totally compatible with the ecosystem (but perfectly valid in the TS point of view), at least not totally identical to those generated without this option + a traditional (with.jsimports) ESM code base.So Ryan, as you are one the deciders of the Typescript team, if
tscdoesn't rewrite paths in.d.tsfiles, while it does rewrite the exact same ones in.jsfiles, is it:rewriteRelativeImportExtensions?Even if my opinion is the first choice, it's just an opinion, not a definitive response. And I need a response, not an opinion, to continue my evaluations 🙂
Thank you for your time!
jnields commentedon Feb 7, 2025
This seems like a bug to me.
If you want to update your build to add ESM support, which is generally why you’d be using this so that you can have imports with extensions, then your build will produce declaration files that look like this:
There will be a file
"./foo.d.ts"but no"./foo.ts"This isn’t necessarily backwards compatible, but it easily could be if you were to just rewrite the extensions for the declaration files as well.
imcotton commentedon Jul 31, 2025
Since the ticket has the Help Wanted label, what is the correct spell to summon the copilot for the help?
Patch type file extensions microsoft/TypeScript#61037
Fix extension rewriting for .d.ts files
paulmillr commentedon Nov 24, 2025
User encountered TS2691 in Angular/Ionic/Capacitor because of this.
stevenvachon commentedon Dec 28, 2025
A year later and still no work on this? Flow might've been a better choice than TypeScript.
In the meantime, continue with extensionless paths to
*.{ts,tsx}files and run:chore: use .ts extensions in library relative imports
everett1992 commentedon Apr 15, 2026
I hit this case while removing
ts-nodefrom the devDependencies of a project published to npmjs.It's published to npm, so it must be compiled to .js and .d.ts files. Node will not resolve .ts files in node_modules, something TypeScript's developers seem in favor of nodejs/node#58429.
But it's useful to run development tests and scripts thru node's native typescript support, which requires
.tsextensions.Compiling for npm requires type stripping rewriting extensions.
tsc --rewriteRelativeImportExtensions produces working .js files, but the .d.ts files reference .ts files which caused typescript errors in consumers of my library.
docs: cite the upstream issue behind the declaration rewriting
build: serve Deno the TypeScript source through a deno export condition
refactor: split library into cesr and keri workspace packages (#38)
fix(core): rewrite relative .ts specifiers in emitted declarations
fix(core): resolve relative specifiers under Turbopack dev (#20)
Patch type file extensions microsoft/TypeScript#61037
Patch type file extensions microsoft/TypeScript#61037
Patch type file extensions microsoft/TypeScript#61037
Patch type file extensions microsoft/TypeScript#61037
Patch type file extensions microsoft/TypeScript#61037