Repository: TypeScript
Issue: Design Meeting Notes, 8/20/2024
Labels: Design Notes


# Reconsidering a flag to rewrite `.ts` to `.js` in emit in light of TS support in Node.js

https://github.com/microsoft/TypeScript/issues/59597#issuecomment-2287466184

* Traditionally, we've said we will never rewrite any module specifier.
* What's changed? `--experimental-transform-types` and `--experimental-strip-types` are now in Node.js.
    * Here, you must reference your files with an explicit `.ts`-like extension.
* Today, we have `allowImportingTsExtensions` to allow this, but you must have `noEmit` turned on.
* People want a mode where they can emit to `.js` but still reference `.ts` files.
    * Why?
        * Maybe you were using these transform types for development, but need to emit to JS for production.
        * Maybe you need to publish to npm (can't load `.ts` from `node_modules`).
* So we are reconsidering TS never rewriting paths.
* What are the rules for when TypeScript can do this?
    * Paths must begin with a `.` or `..`.
    * The path cannot be a declaration file path (i.e. one cannot explicitly reference a `.d.ts` file).
    * The path must be a `.ts`, `.tsx`, `.cts`, or `.mts` file.
* `.tsx`
    * We will rewrite `.tsx` to `.js` if `--jsx` is `react`, `react-jsx`, or `react-jsxdev`.
    * We will rewrite `.tsx` to `.jsx` if `--jsx` is `react-native`.
* Error checking.
    * We will do a naive transform, but we will need to see if something will improperly be transformed.
    * For example, `import foo = require("./foo.ts");` will be transformed to `import foo = require("./foo.js");`, which is incorrect if the original file was `foo.ts.ts`.
    * Can we do something about incorrect`import` and `export` subpaths?
        * We don't rewrite subpaths, but people can write `exports` and `imports` in `package.json` that resolve to `.ts` files. Won't run on publish.
        * Mmmmaybe, we haven't settled on anything on this yet.
* Is the request something like "downleveling"?
    * Kind of. It's for older runtimes, it's for `node_modules`.
    * Are there other less-obvious features that need to be downleveled?
        * Don't want to over-generalize on this problem space.
* Are there other 
    * What about `--outDir`? Shouldn't we rewrite paths relative to `outDir`?
        * If you rewrite `../../other-project/src/foo.ts`, don't you want to rewrite this to `../../other-project/dist/foo.js`?
            * Uh.
    * `moduleSuffixes`?
        * Can ban this one...probably.
* Are we fighting the tide with this stuff? Should we just say the runtime should support `.ts` everywhere and that's what people use?
    * Maybe long-term? There are lots of issues with that, but this is nearer-term.
* What do we do with `import type`?
    * Presumably, we would rewrite these to `.js` as well, right?
    * We can leave them as-is technically.
    * We should test that.
* Lots of hypotheticals around using Deno and Bun and then going broader across runtimes.
    * Is that realistic? dnt probably does this better than we can.
* Are we going to error if users write `.js` imports instead of `.ts`? It's going to error and users are not going to know why.
* We probably should look at if JSR does the same transforms that we're looking to do.
* This is experimental in Node.js. Should this be experimental as well?
    * Supports other tools/use-cases as well.
* Let's talk about dynamic `import(...)` calls.
    * Some of these are statically analyzable, but some are not.
        * e.g. `import(someVariable);`
    * One option is a runtime shim like `__fixExtension`.
    * Another option is to just not rewrite these at all - means you can only have static imports, and users have to write their own shimming logic before calling `import()` on totally dynamic contents.
    * Leaning a little towards just making this work with a helper.
        * tslib?
            * Yes, but you might want this fixed (file extensions might not be recognized).
            * Well users can lock on a tslib.
* This is in theory simple enough - so simple it could be a standalone tool. Which is an argument both for and against doing it.
    * People have written them, but they don't get the error checking.
* Feels like we need answers for
    * `moduleSuffixes`
    * `outDir`
* If people want to use these modes, they usually don't want to use `tsc` in the tight loop anyway, right? Why do people want to write `tsc`? Some other tool can do this rewriting.
    * Declaration files
* How do you avoid the `../../src/foo.ts` vs. `../../dist/foo.js` problem?
    * Is it a problem? Doesn't work today if you reference the input file.
        * But that's the whole story - you're running off of input files. And the way people avoid thinking about this is `imports`/`exports` subpaths in `package.json`, workspaces, or path mappings.
    * Probably needs custom conditions and non-relative paths.
        * Though are there custom conditions that **don't** get triggered within `node_modules`? Because you don't want to resolve to the `.ts` files in `node_modules` (they'll fail at runtime!).
* There are a LOT of issues regarding deployment, project structuring, scaling, etc. that need to be solved. Needs to fundamentally be built into how Node.js itself supports TypeScript.