Typescript has had the "erasableSyntaxOnly" compiler option for a couple versions now. Running it on a medium sized or large code base isn't terrible. With Node now supporting type-stripping, you can run entire large code bases without compilation today after that flag, so there's some benefit to doing it. (If for some reason you need to support an out-of-support Typescript version, eslint has had linter rules that match "erasableSyntaxOnly" for even longer.)
> (class/fields modifiers, function overloading, declare keyword, namespaces)
Most of the class/field modifiers have standard JS ways to do them today (#field for private, [symbolField] for protected/"internal"). The nicest one to have and hardest to replace is `readonly` used to enforce at compile time that a field is only ever set once at initialization. There are workarounds with properties and property syntax and a workaround to use a JSDoc comment.
Function overloading and declare keyword can generally be handled by moving everything to an appropriate .d.ts file. Also a lot of function overloading can be taken care of today in more JS-friendly ways with union types or `unknown` with type guards that better matches the runtime experience of JS. (I realize that there are definitely still edge cases that can be easier to write as function overloads than as `unknown` with type guards, but they seem so much fewer than ever.)
I personally have only found one use case for namespaces in a while that isn't solved with module (re-)architecture (including "exports" at the package level architecture) and/or symbol-named things. That use case is silliness involving passing JSX type information. Typescript is a little weird about how it wants to pick up JSX types. It should still work in a .d.ts and that's on my TODO list of things to try soon (I'm working on a rewrite of a JSX-based view engine where one of the motivations for the rewrite is to get possibly really wild with JSX types because moving from one `jsx` function to many, for interesting reasons).
I know the "gentle merge" of namespace will be missed by some, but the code it generates is easy to reproduce in pure JS and will be very familiar to anyone who did a lot of jQuery era `window.myObject = window.myObject || {}` dances, which were the style at the time and that to get that to type how you need it to you'll need a lot more `as unknown as MyExtendedObject` type dances. But also that's a somewhat better type representation of what you are doing with those sorts of multiply expanded objects.
I was just thinking of the projects I worked in and none of them would be a clean migration to not transpile typescript anymore in development mode.
My main problem would be the typescript class/field modifiers, like you said I use readonly extensively. I didn't know about the "erasableSyntaxOnly" compiler option, I will make sure to turn it on for newer codebases.
> (class/fields modifiers, function overloading, declare keyword, namespaces)
Most of the class/field modifiers have standard JS ways to do them today (#field for private, [symbolField] for protected/"internal"). The nicest one to have and hardest to replace is `readonly` used to enforce at compile time that a field is only ever set once at initialization. There are workarounds with properties and property syntax and a workaround to use a JSDoc comment.
Function overloading and declare keyword can generally be handled by moving everything to an appropriate .d.ts file. Also a lot of function overloading can be taken care of today in more JS-friendly ways with union types or `unknown` with type guards that better matches the runtime experience of JS. (I realize that there are definitely still edge cases that can be easier to write as function overloads than as `unknown` with type guards, but they seem so much fewer than ever.)
I personally have only found one use case for namespaces in a while that isn't solved with module (re-)architecture (including "exports" at the package level architecture) and/or symbol-named things. That use case is silliness involving passing JSX type information. Typescript is a little weird about how it wants to pick up JSX types. It should still work in a .d.ts and that's on my TODO list of things to try soon (I'm working on a rewrite of a JSX-based view engine where one of the motivations for the rewrite is to get possibly really wild with JSX types because moving from one `jsx` function to many, for interesting reasons).
I know the "gentle merge" of namespace will be missed by some, but the code it generates is easy to reproduce in pure JS and will be very familiar to anyone who did a lot of jQuery era `window.myObject = window.myObject || {}` dances, which were the style at the time and that to get that to type how you need it to you'll need a lot more `as unknown as MyExtendedObject` type dances. But also that's a somewhat better type representation of what you are doing with those sorts of multiply expanded objects.