Rewrite relative import extensions with flag by andrewbranch · Pull Request #59767 · microsoft/TypeScript (original) (raw)
This PR adds --rewriteRelativeImportExtensions
to support transforming module specifiers from e.g. "./utils.ts"
to "./utils.js"
. A module specifier will be statically rewritten or shimmed during JS emit if it meets all of these criteria:
- it begins with
./
or../
- it does not end in a declaration file name (
.d.ts
,.d.mts
,.d.cts
,.d.*.ts
) - it ends in
.ts
,.tsx
,.mts
, or.cts
Error checking
Errors are issued in an attempt to catch common mistakes:
- A module specifier will get rewritten but will break after rewriting:
"./foo.ts"
actually resolves to./foo.ts.ts
orfoo.ts/index.ts
"../other-project/src/index.ts"
belongs to another project where outputs go to a different outDir
- A module specifier will not get rewritten but will break after emitting as-is:
"#blah/foo.ts"
resolves tofoo.ts
where the.ts
matches through a wildcard
Syntax support
Scenario | Example input | Operation | Example output |
---|---|---|---|
Import declarations | import "./foo.ts" | Rewrite | import "./foo.js", require("./foo.js") |
Export declarations | export * from "./foo.ts" | Rewrite | export * from "./foo.js" |
Import equals | import foo = require("./foo.ts") | Rewrite | import foo = require("./foo.js") |
Import calls with qualifying literal argument | import("./foo.ts") | Rewrite | import("./foo.js") |
Require calls in JS with qualifying literal argument | require("./foo.ts") | Rewrite | require("./foo.js") |
Import calls with non-literal argument | import(getPath()) | Shim | import(__rewriteRelativeImportExtension(getPath())) |
Require calls in JS with non-literal argument | require(getPath()) | Shim | require(__rewriteRelativeImportExtension(getPath())) |
Import calls with non-qualifying literal argument | import("foo") | None | import("foo") |
Require calls with non-qualifying literal argument | require("foo") | None | require("foo") |
Require calls in TS | require("./foo.ts") | None | require("./foo.ts") |
Indirected require calls | (require)("./foo.ts") | None | (require)("./foo.ts") |
Limitations and future work
This PR doesn’t change how module resolution works, so it’s still possible to reference a .ts
file by a .js
module specifier:
// @Filename: a.ts export {};
// @Filename: b.ts import {} from "./a.js"; // Always ok
We discussed that it’s probably desirable to turn this functionality off under --rewriteRelativeImportExtensions
(and --allowImportingTsExtensions
), since these options are a strong indicator that the user is going to run the input TS files in a TS-native runtime like Bun or node --experimental-strip-types
. That would be a breaking change and isn’t included in this PR.
tslib PR: microsoft/tslib#270
Fixes #59597