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
I wanted to talk about the future of --experimental-transform-types.
The feature has been stable for a while no outstanding issue.
The problem with this flag is that the syntax supported might change due to typescript deprecations (rip module which btw is already not supported just an example), syntax becomes supported in the js spec (Maybe enums one day 😆) etc...
Here a few options:
remove the flag completely (I dont know if its even possible given the massive usage)
Leave the flag experimental forever (I dont like this option)
Mark the flag as stable but document that the changes in the syntax are not semver major therefore it can break)
Mark the flag as stable and mark every syntax change as semver major (😫)
(rip module which btw is already not supported just an example)
Just one narrow correction: the deprecation of the module keyword was not specific to transform-types. It was just a plain carefully-executed TypeScript-wide deprecation. The proof is that if you enable erasableSyntaxOnly in TS 5.9, you can still use module to create type-only ("uninstantiated") namespaces.
A year ago, knowing this deprecation was likely coming in TS 6.0, we took mitigation steps in Amaro/SWC to error on the old syntax. This is why today both strip-types and transform-types are immune to the deprecation.
Would you mind editing to remove this example? Or use strike-through.
module is a fitting example of deprecated syntax which would require a Node.js semver major if the flag were to be marked as stable. Thats (among other more compelling reasons) why I think its not a good idea to mark it as stable. Type stripping would of course have the same problem, but since transform-types supports more syntax, this issue is more likely
Reacted by Jordan Harband, Rob Palmer, Steven and Owen Buckley
Hi there, adding my two cents following @marco-ippolito post on bluesky (I guess that was the intent). The current trajectory of the JS ecosystem seems to be in favor of annotation-based typing:
Therefore, I would pick option 1 (remove --experimental-transform-types)
Type stripping is currently implemented with this caveat:
To discourage package authors from publishing packages written in TypeScript, Node.js refuses to handle TypeScript files inside folders under a node_modules path.
To go further in the annotation-based typing direction, I would create an --experimental-type-stripping-node-modules to enable type stripping for .ts files in node_modules, enabling build-step-free publication of TypeScript code to npmjs.com, à la Deno/jsr
You may know that all Svelte projects migrated from TS to JS+JSDoc because it made everything simpler, tooling-wise. Being able to publish and run TS dependencies with vanilla Node might tip the scale in favor of (erasable) TS over JS+JSDoc
This keeps getting brought up repeatedly, in many different threads (on this repo, node repo). Publishing TS has major downsides, including significant perf hits and incompatibility for TS itself (you really do not want to load everyone else's original TS source), which are solved by running tsc to publish .d.ts files (which, why even publish TS at that point).
JSR is different, because you publish TS, but they build your code for you and distribute .d.ts and .js files. It just moves the build process somewhere else.
I forgot to consider TS in the equation, but I'd say it's solved by isolatedDeclarations. That may slightly degrade the DX (writing type annotations for all exports is cumbersome), but that could be solved with editor tooling (e.g. create/update export type declarations on save). All in all, it would benefit publishers a little (simpler build steps) and consumers a lot (smaller packages, high fidelity types, easy node_modules patching). What do you think?
Mark the flag as stable and mark every syntax change as semver major (😫)
This seems like the most logical solution. Why the 😫 face? Is this challenging to do?
Deprecating syntax needs a deprecation cycle that takes 2 semver majors. It also means we have to maintain multiple release lines of amaro. There is definitely some effort behind, that with strip types we dont have. I would rather remove it than maintain it
Reacted by Gautier Ben Aïm, Steven and Geoffrey Booth
It's a real shame. You removed a well-functioning and stable feature for no good reason.
This is a good example of how you can draw the wrong conclusions by ignoring the context.
The --experimental-transform-types flag should not appear at all in the code placed in the public repository because it is only used for local cli work.
The flag is called --experimental-transform-types, focus on experimental, it was definitely NOT stable.
draw the wrong conclusions by ignoring the context.
You are doing exactly the same thing, ignoring why this flag was removed and the whole context around this issue.
The --experimental-transform-types flag should not appear at all in the code placed in the public repository because it is only used for local cli work.
I don't understand what you mean by this. The flag, from its creation 2 years ago, was NEVER meant to become stable. It was just a way to help people to transition to type stripping.
The fact that the feature has been stable in its implementation does not mean it is safe to mark as stable for users, infact the biggest issue is not the feature implementation itself rather the long term maintainance, which is explained in detail in this issue. That is why it was decided to remove. I'm not some evil developer that wants to gatekeep this feature. It's simply not future proof.
It's irrelevant it's a cli only flag.
OK. I just don't understand why you didn't choose the most advantageous option "C":
Mark the flag as stable but document that the changes in the syntax are not semver major therefore it can break)
Future changes to Typescript may also affect the type description syntax.
The entire maintenance process should be reduced to a single line in the documentation: Node X uses for transpilation Amaro in version Y and is therefore compatible with Typescript Z syntax.
No one expected Node to track changes in TS. It would be enough to update Amaro naturally with each full version of Node (every six months).
This is bananas. All my TypeScript code that uses namespace is now breaking. I, too, thought this would imply "no longer experimental, just stable, no need to specify". Ooof, that was such a convenient feature.
at least alternative is just --import="..." with amaro, so that softens the blow (we use it a lot too at HF, namespaces/enums is one thing, but transpilation enables cool things like await using iirc before they're supported by node itself)
We switched more than a hundred projects of ours over the past year to use the native Node test runner and framework, this completely breaks that for us. I know it is experimental, so it is our fault for relying on it, but I just wanted to leave my two cents anyways. Being able to execute any TypeScript code when testing, including non-erasable syntax, is a thing that is extremely useful and in my opinion even necessary.
Not sure how we should proceed now, but the only options we have are either to go back to installing third-party dependencies and using loaders - which have always been fickle over the years and have caused us major problems multiple times - or to switch away from the native test runner entirely and go back to what we used before.
Also - whether there will be any well-maintained dependencies that do that is questionable since Node did support full TypeScript up until this change here, and now even that it only does partially, I doubt there will be the energy to maintain 3rd party libraries as well as it was done before Node had any support.
Both things are less than ideal, and I do not even know why there was such a big need to remove this anyways, since it was just a flag, the dependency you are pulling in here for this (SWC I think?) didn't get removed and it also doesn't look like it caused huge pain to maintain since it is just a flag?
I would have just kept it in experimental forever if you care about the semantics of it. Removing it just because of the semantics of whether the flag can ever be stable before there are viable alternatives like microsoft/TypeScript#61414 or github.com/tc39/proposal-enum is not a good move.
Reacted by 沈鸿飞, sosoba, Bjarne Grimberg, Eli, Sebastien Barre, Alex Solomaha, Guillaume Besson and Rin Tepis
Not sure how we should proceed now, but the only options we have are either to go back to installing third-party dependencies and using loaders - which have always been fickle over the years and have caused us major problems multiple times - or to switch away from the native test runner entirely and go back to what we used before.
Or use only erasable syntax.
Reacted by Jordan Harband and Marco Ippolito
Reacted by Sebastien Barre, Silas Rech, Segev Finer and Rin Tepis
Of course that is what we are trying to do as a last resort, but we are relying heavily on enums so that would mean breaking a couple hundred packages, so major releases etc. etc. (and that only because we cannot natively run the tests anymore, we are not using --experimental-transform-types in production).
We removed --experimental-transform-types in v26 as semver major instead of a semver minor (experimental APIs don't follow semver). Node v26 will be LTS in 6 months. Node v22 and v24 will still have this flag. There is plenty of time to migrate to strip types. Relying so much on an experimental flag is never a good idea.
Reacted by Jordan Harband and Hunter Tunnicliff
Reacted by Sebastien Barre, Silas Rech, Segev Finer, Guillaume Besson, Rin Tepis and sosoba
Activity
ljharb commentedon Jan 27, 2026
i'd love to see numbers on this!
I'd expect the only viable options are 2, or 4. 1 will upset people who use it even if the usage was small, and 3 contradicts the meaning of "stable".
jakebailey commentedon Jan 27, 2026
I would personally say option 2; "use at your own risk".
marco-ippolito commentedon Jan 27, 2026
Quick search https://github.com/search?q=--experimental-transform-types+NOT+is%3Afork&type=code 1.7K results
ljharb commentedon Jan 27, 2026
Thanks! Is that considered "massive"? What do other experimental flags look like in those results?
aduh95 commentedon Jan 27, 2026
https://github.com/search?q=--experimental-strip-types+NOT+is:fork&type=code shows 5.9k results, https://github.com/search?q=--experimental-require-module+NOT+is:fork&type=code shows 769 results, https://github.com/search?q=--experimental-sqlite+NOT+is:fork&type=code 560 results, https://github.com/search?q=--experimental-websocket+NOT+is:fork&type=code 126 results.
robpalme commentedon Jan 27, 2026
Thanks for getting the numbers @aduh95. I am curious about the numeric thresholds Node uses to make these kinds of decisions.
Just in case option 1 seemed too blunt, there is also...
Option 1.5: "Carefully managed removal". Mark it as deprecated so that people know it will be considered for removal in some future major version.
robpalme commentedon Jan 27, 2026
From OP:
Just one narrow correction: the deprecation of the
modulekeyword was not specific totransform-types. It was just a plain carefully-executed TypeScript-wide deprecation. The proof is that if you enableerasableSyntaxOnlyin TS 5.9, you can still usemoduleto create type-only ("uninstantiated") namespaces.A year ago, knowing this deprecation was likely coming in TS 6.0, we took mitigation steps in Amaro/SWC to error on the old syntax. This is why today both
strip-typesandtransform-typesare immune to the deprecation.Would you mind editing to remove this example? Or use
strike-through.marco-ippolito commentedon Jan 27, 2026
moduleis a fitting example of deprecated syntax which would require a Node.js semver major if the flag were to be marked as stable. Thats (among other more compelling reasons) why I think its not a good idea to mark it as stable. Type stripping would of course have the same problem, but sincetransform-typessupports more syntax, this issue is more likelyGauBen commentedon Feb 11, 2026
Hi there, adding my two cents following @marco-ippolito post on bluesky (I guess that was the intent). The current trajectory of the JS ecosystem seems to be in favor of annotation-based typing:
erasableSyntaxOnlyTherefore, I would pick option 1 (remove
--experimental-transform-types)Type stripping is currently implemented with this caveat:
To go further in the annotation-based typing direction, I would create an
--experimental-type-stripping-node-modulesto enable type stripping for .ts files innode_modules, enabling build-step-free publication of TypeScript code to npmjs.com, à la Deno/jsrYou may know that all Svelte projects migrated from TS to JS+JSDoc because it made everything simpler, tooling-wise. Being able to publish and run TS dependencies with vanilla Node might tip the scale in favor of (erasable) TS over JS+JSDoc
jakebailey commentedon Feb 11, 2026
This keeps getting brought up repeatedly, in many different threads (on this repo, node repo). Publishing TS has major downsides, including significant perf hits and incompatibility for TS itself (you really do not want to load everyone else's original TS source), which are solved by running
tscto publish.d.tsfiles (which, why even publish TS at that point).JSR is different, because you publish TS, but they build your code for you and distribute
.d.tsand.jsfiles. It just moves the build process somewhere else.GauBen commentedon Feb 11, 2026
I forgot to consider TS in the equation, but I'd say it's solved by
isolatedDeclarations. That may slightly degrade the DX (writing type annotations for all exports is cumbersome), but that could be solved with editor tooling (e.g. create/update export type declarations on save). All in all, it would benefit publishers a little (simpler build steps) and consumers a lot (smaller packages, high fidelity types, easy node_modules patching). What do you think?marco-ippolito commentedon Feb 11, 2026
I dont want this to become another conversation about type stripping in node_modules, it's kinda unrelated to the topic
styfle commentedon Feb 11, 2026
This seems like the most logical solution. Why the 😫 face? Is this challenging to do?
marco-ippolito commentedon Feb 11, 2026
Deprecating syntax needs a deprecation cycle that takes 2 semver majors. It also means we have to maintain multiple release lines of amaro. There is definitely some effort behind, that with strip types we dont have. I would rather remove it than maintain it
styfle commentedon Feb 11, 2026
Personally, I haven't needed transform types since strip types is sufficient for my use cases.
To reiterate, the links shared above:
That means around 31% of users need transform. Maybe less than that given strip types is no longer flagged, but still significant.
Removing it might be painful for those users since the would need to switch back to ts-node, tsx, or similar.
Since we can't easily follow semver, I think the next best thing is to keep it experimental forever.
7 remaining items
sosoba commentedon May 6, 2026
It's a real shame. You removed a well-functioning and stable feature for no good reason.
The
--experimental-transform-typesflag should not appear at all in the code placed in the public repository because it is only used for local cli work.marco-ippolito commentedon May 6, 2026
The flag is called
--experimental-transform-types, focus on experimental, it was definitely NOT stable.You are doing exactly the same thing, ignoring why this flag was removed and the whole context around this issue.
I don't understand what you mean by this. The flag, from its creation 2 years ago, was NEVER meant to become stable. It was just a way to help people to transition to type stripping.
sosoba commentedon May 6, 2026
Feature <> flag. Let me quote an authority:
I will explain with an example.
src/example.tspackage.jsonDo you see the use of a flag here? Probably not. You will only notice it in the developer console:
marco-ippolito commentedon May 6, 2026
The fact that the feature has been stable in its implementation does not mean it is safe to mark as stable for users, infact the biggest issue is not the feature implementation itself rather the long term maintainance, which is explained in detail in this issue. That is why it was decided to remove. I'm not some evil developer that wants to gatekeep this feature. It's simply not future proof.
It's irrelevant it's a cli only flag.
sosoba commentedon May 6, 2026
OK. I just don't understand why you didn't choose the most advantageous option "C":
Node X uses for transpilation Amaro in version Y and is therefore compatible with Typescript Z syntax.No one expected Node to track changes in TS. It would be enough to update Amaro naturally with each full version of Node (every six months).
sebastienbarre commentedon May 7, 2026
This is bananas. All my TypeScript code that uses
namespaceis now breaking. I, too, thought this would imply "no longer experimental, just stable, no need to specify". Ooof, that was such a convenient feature.coyotte508 commentedon May 7, 2026
at least alternative is just
--import="..."with amaro, so that softens the blow (we use it a lot too at HF, namespaces/enums is one thing, but transpilation enables cool things likeawait usingiirc before they're supported by node itself)lenovouser commentedon May 9, 2026
We switched more than a hundred projects of ours over the past year to use the native Node test runner and framework, this completely breaks that for us. I know it is experimental, so it is our fault for relying on it, but I just wanted to leave my two cents anyways. Being able to execute any TypeScript code when testing, including non-erasable syntax, is a thing that is extremely useful and in my opinion even necessary.
Not sure how we should proceed now, but the only options we have are either to go back to installing third-party dependencies and using loaders - which have always been fickle over the years and have caused us major problems multiple times - or to switch away from the native test runner entirely and go back to what we used before.
Also - whether there will be any well-maintained dependencies that do that is questionable since Node did support full TypeScript up until this change here, and now even that it only does partially, I doubt there will be the energy to maintain 3rd party libraries as well as it was done before Node had any support.
Both things are less than ideal, and I do not even know why there was such a big need to remove this anyways, since it was just a flag, the dependency you are pulling in here for this (SWC I think?) didn't get removed and it also doesn't look like it caused huge pain to maintain since it is just a flag?
I would have just kept it in experimental forever if you care about the semantics of it. Removing it just because of the semantics of whether the flag can ever be stable before there are viable alternatives like microsoft/TypeScript#61414 or github.com/tc39/proposal-enum is not a good move.
Sainan commentedon May 9, 2026
"Oh no, we might have to make breaking changes. How do we fix it? Ah yeah, let's just make a breaking change."
GeoffreyBooth commentedon May 11, 2026
Or use only erasable syntax.
lenovouser commentedon May 11, 2026
Of course that is what we are trying to do as a last resort, but we are relying heavily on enums so that would mean breaking a couple hundred packages, so major releases etc. etc. (and that only because we cannot natively run the tests anymore, we are not using
--experimental-transform-typesin production).Waiting for something like microsoft/TypeScript#61414 to land would have been sensible.
marco-ippolito commentedon May 11, 2026
We removed
--experimental-transform-typesin v26 as semver major instead of a semver minor (experimental APIs don't follow semver). Node v26 will be LTS in 6 months. Node v22 and v24 will still have this flag. There is plenty of time to migrate to strip types. Relying so much on an experimental flag is never a good idea.SCLeoX commentedon May 17, 2026
marco-ippolito commentedon May 18, 2026
You have the choice to use Node v24 for the next two years and migrate to strip types or use Amaro. I'm locking this conversation.