TypeScript
TypeScript copied to clipboard
[experiment] Rewrite relative import extensions with flag
⚠️ This PR does not indicate intent to ship; I just needed a published experimental build of it for some experiments and demos. ⚠️
@typescript-bot pack this
Starting jobs; this comment will be updated as builds start and complete.
| Command | Status | Results |
|---|---|---|
pack this |
✅ Started | ✅ Results |
Hey @andrewbranch, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:
{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/163457/artifacts?artifactName=tgz&fileId=2225118E5057943A4B80A3A9D8FE2EA5696226BA40FE09011C7C2241BF80844302&fileName=/typescript-5.7.0-insiders.20240826.tgz"
}
}
and then running npm install.
There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;
Looks like you're introducing a change to the public API surface area. If this includes breaking changes, please document them on our wiki's API Breaking Changes page.
Also, please make sure @DanielRosenwasser and @RyanCavanaugh are aware of the changes, just as a heads up.
@typescript-bot pack this
Starting jobs; this comment will be updated as builds start and complete.
| Command | Status | Results |
|---|---|---|
pack this |
✅ Started | ✅ Results |
Hey @andrewbranch, I've packed this into an installable tgz. You can install it for testing by referencing it in your package.json like so:
{
"devDependencies": {
"typescript": "https://typescript.visualstudio.com/cf7ac146-d525-443c-b23c-0d58337efebc/_apis/build/builds/163603/artifacts?artifactName=tgz&fileId=366D2974C150D261A1702BA0C2511DBAF6432824433FEBBEB4D1A438DE1953C602&fileName=/typescript-5.7.0-insiders.20240917.tgz"
}
}
and then running npm install.
There is also a playground for this build and an npm module you can use via "typescript": "npm:@typescript-deploys/[email protected]".;
The original issue was locked; it would be nice for someone with permissions to comment there so that people who were following there get this update.
@RyanCavanaugh I happened upon your final post here: https://github.com/microsoft/TypeScript/issues/49083#issuecomment-1435399267 minutes before you commented and referenced this PR.
I'm curious what changed from your reasoning a year ago as to why this would never be a feature?
NodeJS shipping --experimental-strip-types means there's now an actual runtime scenario where you need both JS and TS extensions
Note that if you're using this in any other situation than that, you likely have a misconfiguration or misunderstanding of some kind, and I'll be telling you as much in a future issue when you report that e.g. this "doesn't work" across package boundaries.
I have tested TS 5.7.0-dev.
It does not rewrite .d.ts files.
My library preset on 5.6.2:
/* Library preset */
"module": "NodeNext",
"moduleResolution": "NodeNext",
"noEmit": false,
"declaration": true,
and new one on 5.7.0-dev:
/* Library preset */
"module": "NodeNext",
"moduleResolution": "NodeNext",
"allowImportingTsExtensions": true, // <- new
"rewriteRelativeImportExtensions": true, // <- new
"noEmit": false,
"declaration": true,
It works, I can use tsc (after changing .js to .ts in imports in all files).
Also, now I can run TS files with deno without using --unstable-sloppy-imports which prints annoying warnings.
However, imports inside .d.ts files have .ts ending now. There were no rewriting.
Or is it OK? (I didn't check if there would be .d.ts files to work correctly after installing a package with such .d.ts files.)
Anyway, I think that both configs should produce absolutely the same result (.js and .d.ts files) after using tsc.
Imports in .d.ts files are allowed to use .ts extensions regardless of config, so I wouldn't really consider that a bug.
It's a bug. Non-rewritten imports in d.ts. break (partially) the code assistance in an IDE.
It's OK:
(
npm install @alttiri/[email protected])
After using rewriteRelativeImportExtensions:
(
npm install @alttiri/[email protected] --registry=https://npm.pkg.github.com)
In this case, the IDE no longer highlights the function names, nor does it show the function signature.
The imports in .d.ts also must be rewritten.
Because all d.ts files of libs are compiled with tsc have imports end with .js, never with .ts.
Because allowImportingTsExtensions was never compatible with "moduleResolution": "NodeNext" + "noEmit": false" (until this new rewriteRelativeImportExtensions appeared.)
Also, it currently (?) does not support aliases which resolve to a relative path.
{
"extends": "../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["../*"]
}
}
}
I get the follow error for import {sleep} from "@/index.ts";:
TS2877: This import uses a '.ts' extension to resolve to an input TypeScript file, but will not be rewritten during emit because it is not a relative path.
Also, it currently (?) does not support aliases which resolve to a relative path.
This is 100% intentional
Is it a problem to resolve the alias first and only after that check if it is a relative path or not?
It doesn't seem like something that is difficult to implement. Just only one extra simple action.
I don't think the setup you have there works under --experimental-strip-types. https://github.com/microsoft/TypeScript/pull/59767#issuecomment-2383844756
Okay, I have checked it with the latest Node.js (v22.9.0) too (I tested it with Deno before).
It works (as expected).
I can't replicate what you're doing there
// with
// import * as bar from "./bar.ts";
node --experimental-strip-types foo.ts
hi
vs
// with
// import * as bar from "@/bar.ts";
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@/bar.ts' imported from D:\Throwaway\est-test\foo.ts
The purpose of the flag is to rewrite paths which are syntactically relative, not "semantically" relative (whatever that would even mean).
Hey, I was reading the table in the PR description and I'm getting confused by these two lines:
Scenario Example input Operation Example output Require calls in JS with qualifying literal argument require("./foo.ts")Rewrite require("./foo.js")Require calls in TS require("./foo.ts")None require("./foo.ts")
Does it mean that require("./foo.ts") will be rewritten if it's inside a JS file, but not if it's inside a TS file?
Yes. Plain require calls aren’t recognized as special in TS files. You’ll notice in JS that require("./foo") performs module resolution (the compiler knows the type to return), but in TS, require isn’t even allowed unless it’s declared as a global function, in which case that function’s return type is used (usually any).
Just out of curiosity, I’m facing an issue where my .d.ts files don’t have an extension in the path. For example: export * as v1alpha2 from './v1alpha2/index.gen';. Why is the .ts extension mandatory to transform it into .js? Thank you.
@RyanCavanaugh
Imports in
.d.tsfiles are allowed to use.tsextensions regardless of config, so I wouldn't really consider that a bug.
While .d.ts files may allow .ts extensions in imports without configuration, wouldn't this break backwards compatibility for libraries targeting TypeScript 4 support since allowImportingTsExtensions wasn't introduced until TypeScript 5?
@andrewbranch @RyanCavanaugh Shouldn't calls to import.meta.resolve()/require.resolve() also be shimmed as part of this flag? The MDN docs suggest this should be the case.