Skip to content

The future of --experimental-transform-types #51

Closed

Description

@marco-ippolito

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 (😫)

WDYT @nodejs/typescript

Activity

  1. ljharb commented on Jan 27, 2026

    @ljharb
    SponsorMember

    massive usage

    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".

  2. jakebailey commented on Jan 27, 2026

    @jakebailey
    Member

    I would personally say option 2; "use at your own risk".

  3. marco-ippolito commented on Jan 27, 2026

    @marco-ippolito
    MemberAuthor

    massive usage

    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".

    Quick search https://github.com/search?q=--experimental-transform-types+NOT+is%3Afork&type=code 1.7K results

  4. ljharb commented on Jan 27, 2026

    @ljharb
    SponsorMember

    Thanks! Is that considered "massive"? What do other experimental flags look like in those results?

  5. aduh95 commented on Jan 27, 2026

    @aduh95
  6. robpalme commented on Jan 27, 2026

    @robpalme

    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.

  7. robpalme commented on Jan 27, 2026

    @robpalme

    From OP:

    (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.

  8. marco-ippolito commented on Jan 27, 2026

    @marco-ippolito
    MemberAuthor

    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

  9. GauBen commented on Feb 11, 2026

    @GauBen

    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

  10. jakebailey commented on Feb 11, 2026

    @jakebailey
    Member

    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.

  11. GauBen commented on Feb 11, 2026

    @GauBen

    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?

  12. marco-ippolito commented on Feb 11, 2026

    @marco-ippolito
    MemberAuthor

    I dont want this to become another conversation about type stripping in node_modules, it's kinda unrelated to the topic

  13. styfle commented on Feb 11, 2026

    @styfle
    SponsorMember

    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?

  14. marco-ippolito commented on Feb 11, 2026

    @marco-ippolito
    MemberAuthor

    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

  15. styfle commented on Feb 11, 2026

    @styfle
    SponsorMember

    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.

  16. 7 remaining items

  17. sosoba commented on May 6, 2026

    @sosoba

    It's a real shame. You removed a well-functioning and stable feature for no good reason.

    Image 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.

  18. marco-ippolito commented on May 6, 2026

    @marco-ippolito
    MemberAuthor

    well-functioning and stable feature

    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.

  19. sosoba commented on May 6, 2026

    @sosoba

    well-functioning and stable feature

    The flag is called --experimental-transform-types, focus on experimental, it was definitely NOT stable.

    Feature <> flag. Let me quote an authority:

    Image

    I don't understand what you mean by this.

    I will explain with an example.

    src/example.ts

    class Example {
      constructor(protected readonly url: URL) {} // need type transform
    }

    package.json

    {
      "exports": "./dist/example.js",
      "scripts": {
        "preversion": "tsc"
      }
    }
    

    Do you see the use of a flag here? Probably not. You will only notice it in the developer console:

    node --experimental-transform-types ./src/example.ts
  20. marco-ippolito commented on May 6, 2026

    @marco-ippolito
    MemberAuthor

    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.

  21. sosoba commented on May 6, 2026

    @sosoba

    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)

    1. Future changes to Typescript may also affect the type description syntax.
    2. 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).

  22. sebastienbarre commented on May 7, 2026

    @sebastienbarre

    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.

  23. coyotte508 commented on May 7, 2026

    @coyotte508

    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)

  24. lenovouser commented on May 9, 2026

    @lenovouser

    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.

  25. Sainan commented on May 9, 2026

    @Sainan

    "Oh no, we might have to make breaking changes. How do we fix it? Ah yeah, let's just make a breaking change."

  26. GeoffreyBooth commented on May 11, 2026

    @GeoffreyBooth
    Member

    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.

  27. lenovouser commented on May 11, 2026

    @lenovouser

    Or use only erasable syntax.

    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).

    Waiting for something like microsoft/TypeScript#61414 to land would have been sensible.

  28. marco-ippolito commented on May 11, 2026

    @marco-ippolito
    MemberAuthor

    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.

  29. SCLeoX commented on May 17, 2026

    @SCLeoX
  30. marco-ippolito commented on May 18, 2026

    @marco-ippolito
    MemberAuthor

    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.

  31. locked and limited conversation to collaborators on May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions