Any pro typescripter have any tips for how best use it in existing Node/React codebase?
This article mentions material-ui and styled-components. My experience with typescript has been cumbersome with these libraries. A lot of time is spent figuring out what ”types” to return. I find this very difficult in most cases and not fun at all.
I figure there must be something wrong in my approach or in my ts config (no explicit any).
In short. How to best handle styled-components/material-ui/other library in ts environment? Or is typescript just to much overhead in these usecases?
I use typescript daily with libraries like those you mentioned. Typescript is not too much overhead, its a huge improvement in the overall developer experience.
The main issue I've had with these libraries and typescript is compiler/IDE performance, which 3.9 seems to suggest improvements.
I'm not quiet sure what issues you are facing without some examples. Given you are listing react libraries, the react community discord server might be a good place to ask specific questions. They have library and typescript specific channels to ask beginner questions in:
Thanks for your replies. Glad to hear it's working well for you. I want to learn it myself. Was hesitant to ask questions here because this is not Stackoverflow :-) I will check out the discord.
Just to follow up what I meant i created a quick gist. Not working code but maybe can explain it a bit better.
What I mean as an example is this. I create a function that uses styled-components. I have no idea what the return type should be at first. I must dig into internals of styled-components and eventually find something like "AnyStyledComponent" which is basically the same as "Any" but for styled-components.
> How to best handle styled-components/material-ui/other library in ts environment?
I’m using Blueprint 3 in TS environment and it’s really nice to get feedback about, say, wrong props passed to one of its styled components right as you type.
> My experience with typescript has been cumbersome with these libraries. A lot of time is spent figuring out what ”types” to return. I find this very difficult in most cases and not fun at all.
Whether your code is statically typed or not, you generally have to be aware of which data structure goes where—otherwise it’s easy to break things.
When code is statically typed, most things break at compile time, enabling your IDE to give immediate feedback. I find the flow much more pleasant if I don’t have to hunt down runtime errors resulting from using a library (BP3 or anything else) in a wrong way.
There is some upfront effort in specifying types explicitly where compiler can’t figure it out or does so mistakenly; how fun that is might depend on your personality and established habits. In addition, I believe it heavily depends on tooling—I like using TS in VS Code environment, but TS with Vim (which I’ve been using for many years) was somewhat of a hell.
Once in a while I come across an obscure library without TS typings, in which case I would generally provide a `.d.ts` file for it, starting with a catch-all `any` type for its exports, later potentially specifying it further if useful and feasible. This is by far the least fun part.
Oh thanks! Yes my "problem" is mostly around what types to return or rather how to find them. To be aware that separate types package must be installed is definitely something to get into habit.
I wasn't aware of the `.d.ts` files. It sounds a lot like what I was looking for! Thanks again for your feedback and help :-)
If finding types is especially difficult, it may depend on a particular library (poorly documented types) and on the tooling you use (e.g., VS Code allows to quickly jump to definition/implementation/etc. on any imported class or component in your code, which often takes you to the place in that library where you can find out which types you need and where to import them from; it was a bigger pain in Vim).
By the way, keep in mind that it is often unnecessary to specify types explicitly because TS can infer them from context. I used to specify way too many types when I was initially learning TS.
I find you generally want the @types/ dependencies in the same package.json array as the related dependency (ie, if lodash is a devDependency then `npm i -D` away, but if it is a proper dependency it generally makes sense to `npm i @types/lodash`). Different project's mileage will of course vary, but it makes it easier for downstream dependencies.
> Once in a while I come across an obscure library without TS typings, in which case I would generally provide a `.d.ts` file for it, starting with a catch-all `any` type for its exports, later potentially specifying it further if useful and feasible. This is by far the least fun part.
If you have time, I have a question. Note that my professional exposure to Typescript projects is minimal.
I've built a Javascript library which lives in GitHub, NPM, etc (I won't spam the link). It is entirely module-based Javascript.
My understanding is that while Typescript-based projects can use non-TS JS libraries (because TS is a superset of JS), using that library would require more work - initial code, and maintenance - than using an equivalent library either written in TS, or one that includes a TS Declaration File.
If yes to the above, then - given that I'm serious about my library and want other people to use it if it meets their project needs - I assume I need to write a .d.ts Declaration File (or maybe several?) for it.
- How much initial work are we talking here: weeks? Months?
- After the initial work, how much additional work is required to maintain the .d.ts files(s)?
- How much damage could a poorly written .d.ts file do to a library?
- I've seen the Microsoft documentation[1] and ... this looks like a massive amount of work for my library. I know how popular and useful TS has become but, at the end of the day, would I be wasting my time doing what would be, for me, unpaid work?
I've written a lot of .d.ts files, hopefully I can help.
> My understanding is that while Typescript-based projects can use non-TS JS libraries (because TS is a superset of JS), using that library would require more work - initial code, and maintenance - than using an equivalent library either written in TS, or one that includes a TS Declaration File.
More work, yes, but often not a lot of it depending on need. (You can just tell Typescript some modules are `any` and treat them as a black box.)
It's not so much "more work" as it is "less confidence". If you are looking for trust from TS developers in your library, a TS Declaration is API documentation directly in their IDE that does basic sanity/usage checks for them.
> How much initial work are we talking here: weeks? Months?
I find it is usually in the order of hours. The variables are the size of your library and in particular its external API surface and how well your API is already documented. A .d.ts file is just another sort of API documentation. If you've got good JSDOC comments, for instance, that does a lot of the work already. In some cases you can get a .d.ts file for "free" from Typescript if you follow a couple patterns in your JSDOC comments and run Typescript on your JS files. (It might also give you errors where your code doesn't agree with type hints in your JSDOC comments, which you may or may not find useful to discover potential bugs or edge cases in your code.)
> After the initial work, how much additional work is required to maintain the .d.ts files(s)?
It depends on your API changes, especially breaking changes. I've told a number of projects to feel free to @ me when they make API changes and I'll PR a .d.ts update and it's rarely more than a couple minutes to look at what their breaking API changes are and what update what needs to be updated.
> How much damage could a poorly written .d.ts file do to a library?
Again, it's mostly a "loss of confidence" style issue. A poorly written .d.ts isn't going to stop a Typescript user from using your library, it's mostly at worst just going to get in their way and they have to use an escape valve (such as a cast to `any` telling Typescript to get out of the way) and it is no worse than having no .d.ts.
Again, if it helps to think of it as API documentation: a bad .d.ts file is like finding an out of date API document for an old version of the API. It can still offer sign posts to what the expected API is supposed to be, it just requires the user of the library to distrust that documentation and either read the source directly or find other documentation sources (StackOverflow or example code from other users, for example).
> I've seen the Microsoft documentation[1] and ... this looks like a massive amount of work for my library. I know how popular and useful TS has become but, at the end of the day, would I be wasting my time doing what would be, for me, unpaid work?
As with any open source work it is a trade-off and you need to make that determination based on what you are comfortable with maintaining. That's why whenever I've written .d.ts files for libraries I don't maintain, I make sure to explain the maintenance effort, often volunteer to try to do my best to keep it maintained, and also realize and respect that not every library wants to maintain their own .d.ts.
It's also why you don't necessarily need to build the types yourself if you aren't (yet) comfortable learning Typescript or switching to Typescript. (Aside: I find that curiosity in adding your own .d.ts file is often a baby step for learning where Typescript helps you in making a better library, and some of the projects I first helped maintained a .d.ts eventually learned and switched to Typescript themselves.)
If you can find a user of your library that uses Typescript, they may already have a partial type definition you can start from and/or be willing to help...
On a tangent, but do you have any recommended readings specifically on writing .d.ts? I don't have a lot of experience on typed languages and I'm not too comfortable writing them, but I realize the value of having them on my project.
I would suggest starting on the experience with typed languages in general first. Starting with the beginning of the Typescript handbook and trying working with things for instance directly in the Typescript Playground. You are going to want all of the basics when writing a .d.ts, and sometimes you aren't going to need much more than the basics.
The other thing I'd recommend is if your focus really is just specifically on writing .d.ts files, and you aren't expecting to use more Typescript directly yourself: get more familiar with and start regularly using JSDoc comments. Typescript in JS mode already understands and can do a lot with JSDoc comments. As I mentioned, it will sometimes give you a fully formed .d.ts if you ask and you have enough JSDoc comments, you'll even get the advantage of some of its type analysis in your project (not as much as if you were writing Typescript directly, but more than just a linter will do). If you use an editor such as VSCode where the JS experience is already backed by the Typescript language service you'd start to see some things almost Typescript-like light up in your development experience as you add more JSDoc comments (maybe even to help explain why you might want to use more Typescript directly).
My focus is not specifically on just writing .d.ts, but mostly being capable enough to adapt JS libraries and type them for my needs. Thanks for the recommendation, will muck around with TS for now.
Thank you! This is a fantastic response (now bookmarked).
I think it best not to do the work now - the library is still evolving and keeping the basic documentation up-to-date (inline comments, but not in JSDOC format) is already an overhead. But this is something I'll need to address at some point. I'll add it to the library's roadmap.
Sort of... Your maintenance burden just becomes higher as a consumer of the library because you can't rely on the compiler to tell you if something goes wrong. But if you have a good testing harness you'll probably figure that out eventually anyways.
To generate typings for your library, you can start with converting from jsdoc if you have docstrings with types, or if you want to infer types at runtime during a testing suite you can use something like https://github.com/microsoft/dts-gen
I've never used dts Gen but it looks promising as a starting point. But as an additional point, only the public functions and classes really need type declarations, so unless you export all of your functions that could cut down on the burden to write up the types.
Yes, that’s one of my major gripes of Typescript. Once you use something like Emotion you spend a lot of time deciphering the compiler errors. I am told it will be better in the new version. Let’s see if I can find an example
>A lot of time is spent figuring out what ”types” to return.
Typescript infers return types, so even if you don't write out a return type, it will still be fully typed.
If you still want to specify the return type, you can take advantage of IDE support. Write the function without an explicit return type, then you can hover over it to see the inferred type, then copy the type.
In my preferred IDE (PyCharm), it's even easier since there's a lightbulb action for it. Alt+Enter > "Specify return type explicitly" > Enter
My two cents: Learn to write Typescript, not Javascript.
There are Javascript patterns that just don't type well. There are other ways to write your code that will be easier to fit into the type system. It might be more verbose and less reusable at times, but it ends up being a worthwhile tradeoff.
That's general advise and might not apply to the libraries you mention, but it's worked well for us to explicitly call out the differences.
Yes, my experience was similar (note, last time I worked with Typescript was about a year ago). It was difficult to use libraries with higher order components or just abstractions in general: redux/thunks, formik, materialui, ... I didn't want to use `any` if at all possible, but instead wanted to have properly defined types.
For example, using thunks, one can pass actions directly, or functions that resolve to an action. So, when you're chaining them, it becomes fiddly with types. Compiler complaining about some type or just resolving to any type. I've spent quite some time on that one. Similarly with Formik, I wanted to have generic validators and generic way of applying those validators ... another one that cost me hours to get through and I wasn't satisfied with the result.
But in the end I've felt that while I've become somewhat proficient with Typescript, I was still quite slow to pump out screens and features. And honestly, I didn't enjoy working with it.
(Then there is another can of worms, which is dpendencies and their typings, where it happened that some minor version was bumped and it broke the typings of another library that depended on previous one. So, you might ask, why don't you just pin the dependencies that work together? Well, sometimes an important bug is fixed in a library and you want to upgrade, but you can't, because a person unrelated to library maintainer that handles typings hasn't upgraded them yet ...)
> It was difficult to use libraries with higher order components or just abstractions in general
It's probably a good idea to learn how to use generics (type parameters) effectively. For me, it helped immensely to think of them as basically declarative functions in the type system, with the generic/type parameter being just like a function parameter. The cool thing is that while you have to declare them on a function, a lot of times they can be inferred at the call site. With higher level abstractions, most of the time the types just flow through these generics and you get what you want at the other side just based on inference.
Note that our new official Redux Toolkit package [0] is written in TS and specifically designed to minimize the amount of types you have to declare in your code, and we have TS-specific guide pages in each of the Redux library docs sites [1] [2] [3], and
> I figure there must be something wrong in my approach or in my ts config (no explicit any).
This is a heretic/unpopular opinion, but I think especially for existing JS/React projects, the laxest possible TS setting is the way to go.
You should be able to get to no type errors in your existing JS project with not too many changes. In these contexts (existing projects) I like to think of TS as more editor experience support than seperate language. Modern React is very friendly to TS automatic type inference, so IMHO you should be getting decent benefits from typescript without annotating anything at all. And instead of fixing complicated type errors for no real gain, just // @ts-ignore and move on.
I don't know what your specific issue is with styled-components. Should work pretty much out of the box? My suggestion would be to use CSS objects over string literals because that way you get typechecking for your CSS.
i‘ve read things to the effect of "if you don‘t use noImplicitAny and strictNullChecks you don‘t understand typescript" a bunch but I‘m glad to see the other approach is popular as well.
IMO this is a very pragmatic approach to converting a large project from JS to TS. It's the approach I've been using to gradually convert large existing codebases over to TS without committing to a huge up-front refactor.
Definitely agree with you about the IDE experience, just that alone is enough for me to justify the transition.
I used this approach in a project I migrated to TypeScript as well. My strategy was to start loose, fix those warnings, and then gently turn up the rigor when I had the energy to fix the resultant warnings.
I like typescript as it fixes a lot of JS quirks - that's good when you have to write code transpiled to JS.
However coming from languages where types are a first element of the language (c++, rust, go...), I often miss a lot of features in typescript (e.g. type conversion overload, generic specialization, etc...)
I know that by design Typescript doesn't want those features and I understand the rationale behind it. I'm just wondering if I'm the only one in that case and if someone would know a language transpiling (not compiling) to JS more appropriate to my tastes (and hence with different goals).
ReasonML is a pleasure to work with, and if reveryui gets momentum I will surely write gui desktop applications with it (I already use it to write compiled applications, under the hood is just ocaml).
Basically all web languages compile/transpile* to JS since that's the only thing with wide support, at least until WASM is 100% equivalent.
What's your definition of transpiling and what are you looking for?
* I personally find the difference meaningless, lots of languages use intermediate compilation targets like C or JS or LLVM IR or assembly so transpiling and compiling mean the same thing to me
I have been using Haxe for side projects for around 5 years now, and continue to be impressed at its power, despite syntactically being quite a simple language. It's refreshing for me to go back to a Haxe codebase after looking at Typescript or Swift code, and it highlights how bloated other programming languages are becoming. A spread operator would be nice though :)
Personally, I prefer to stay with vanilla (not transpiled) Javascript parsed and validated by typescript via an IDE plus JS Doc documentation. The only language that would love to switch with the drawback of transpilation would be Purescript, but a too-small community and too low performance (compile and runtime) at the moment.
Dart is much closer to TypeScript than C++/Rust in terms of static typing, it just fixes some of the JS painpoints because it's not designed to be a 1:1 mapping to JS.
Did anyone try the J2CL Java to Closure JavaScript transpiler (https://github.com/google/j2cl)? A side benefit of this is to completely eliminate Javascript vs Java joke
Check out ReasonML, created by the creator of React (Jordan Walke). It's powerful, stable, fast. Messenger.com is powered by Reason: https://reasonml.github.io/
Can you give a concrete example of the kind of code you'd like to write that you can't write in Typescript?
Types absolutely are a first class citizen in TypeScript. Especially coming from Go, which doesn't even support generics, Typescript is really quite powerful. It even has support for ADTs via discriminated unions, which gives you the same power of enums with associated types that you'd get in Rust/Swift.
Is it possible the reason you feel like Typescript doesn't have Types as a first class citizen is because it leverages structural typing rather than nominal typing?
Not op, but I have experience with TS and some things are more difficult than they should be. For me the biggest issue is the lack of typesafe deserialisation. This makes it super painful to do IO (of which there's _a lot_ of in the serverless infrastructure I'm currently working on). While you can validate with a manually written type guard, that's a pain... It would great if you could do JSON.parse<T>() and have TS auto-generate the type guard for you...
There's also no easy way to switch on union types (à la ocaml), sure you can define an enum and use a JS switch, but that's not as nice, and enforcing exhaustiveness of the switch requires some type hackery with `never`...
Typescript has type erasure meaning that after compilation all information about types is lost.
This means that you loose:
* runtime type reflection
* Reified generics
Half of the changes are due to the language server implementing refactoring and other similar stuff.
This shows clearly why the language server protocol is such a bad design decision and so broken — every language has to implement it itself, and there are no shared features or functionality across languages.
Coming from IDEA, where the exact same refactoring functionality and features work no matter if using typescript, kotlin, Rust, C#, golang or dart, exactly identical in all ways, this has been a huge issue for myself.
Languages Servers should just expose a clean standardized AST format, representing standardized nodes, and this should in turn allow the IDE to act upon this (which would immediately be represented in changed source).
I feel like this is wishful thinking. There is no way you can abstract away so many differences between languages for this to work effectively (or anywhere near as good as a tailor fitted refactoring engine to specific languages)
IDEA does a lot of language specific stuff, it just unifies the UX. Which is what language servers aim anyway.
BTW, I'm a long term user of powerline-go. Fantastic piece of software!
> IDEA does a lot of language specific stuff, it just unifies the UX. Which is what language servers aim anyway.
Yeah, but with IDEA I have the exact same functionality for Rust, Typescript or Java, while the language servers will never agree on the exact same functions being called the same and doing exactly the same. It means relearning your editor every time you switch your language.
I realize I’m probably in the minority as a person who writes basically every project in another language, whichever happens to work best for the project, while most others probably use only a few languages for most of their career, but it’s still annoying.
All you're saying is that IDEA is currently more mature than language server support for most languages. That's obvious, and it doesn't say anything about whether the language server design & protocol itself is good or bad. I don't see anything inherently more generic or extensible about IDEA, they're just further along with more languages implemented.
On top of that most LSP implementations are open source which lowers the cost of entry for developers and avoids lock-in with proprietary IDE's. And the well specified network protocol makes it much more flexible to different dev setups (e.g. run the LSP on more powerful cloud/remote hardware for large apps, use it with docker-based development setups, etc).
So I would argue the exact opposite, the model of proprietary IDE's building walled gardens around so much useful developer tooling for otherwise open-source languages and ecosystems, is what is broken.
What I’m mostly saying is that with such a heterogeneous group of LSPs, they’ll never end up providing the same options — they’ll name them differently, they’ll work differently, etc.
Every editor works the same now — but every language completely different. A user writing JS in vim can write it the same way in VSCode or Atom, but a user using Atom to write JS can’t write Rust in Atom the same way.
I’d love to see a different LSP protocol, one where the LSP exposes much more information, and the editor implements the functionality on top of that, so every language works the same.
Technically, that's also is a disadvantage though, Intellij doesn't have constraints because it only needs to cater its IDEs.
But to your point, LSP have brought the IDE experience to others programming editors. Ex: Emacs now can do everything VSCode does for JS because of LSP.
Sounds like you should write a language server that uses a clean, standardized AST format for a number of languages under the hood. That sounds like a good way to trial the approach.
IMO, until TypeScript gets the following features, it's not worth using:
- Native TypeScript runtime interpreter in Deno (TypeScript alternative to Node.js).
- Native TypeScript runtime interpreter in all major browsers.
- At least 20% performance improvement over plain JavaScript.
The build step has to go away because:
- Source maps are unreliable, bulky, slow and add too much complexity for some environments; many environments fail at using them correctly and this can make it difficult to debug code. Being forced to debug ugly transpiled JavaScript is unacceptable and should never happen.
- It's slow to work with. TypeScript often claims to be 'scalable' but reality is that large projects often take multiple minutes to build for every change. There are no good incremental build solutions which also do proper type checking. There is no runtime type checking.
Native browser support is also essential. The bundling step makes in infeasible to freely mix and match modules written in the two languages in a way which is debuggable.
Microsoft should look into Adobe Flash's ActionScript 3 migration from ActionScript 2 for inspiration (both based on ECMAScript spec BTW, just like JavaScript/TypeScript).
I remember ActionScript 3 clearly because it was able to deliver a 40% speedup AND runtime type checking...
In spite of these huge benefits, I remember that some developers were still hesitant to switch to ActionScript 3! This new generation of developers has clearly lost its ability for critical thinking - I find the current complete lack of resistance to TS is very strange.
There are a lot more reasons to resist JS to TS migration compared to AS2 to AS3 migration.
I remember in AS2, most people were not declaring types in their code (even though there was support for compile-time type checking). Only in AS3 people started adding Type annotations to their code.
> IMO, until TypeScript gets the following features, it's absolutely not worth using
That doesn't make sense. Browsers are unlikely to add native typescript support in the foreseeable future; whereas meanwhile typescript offers huge benefits compared to untyped javascript when it comes to large codebases and refactorings.
>> that doesn't make sense. Browsers are unlikely to add native typescript support in the foreseeable future;
It's not my fault that browsers are not going to do it. It doesn't change the fact that it is necessary and that TS is useless without it (the cons outweigh the pros).
>> huge benefits compared to untyped javascript when it comes to large codebases and refactorings
I've provided you at least 1 robust argument why this is not the case. You've provided 0.
I can provide another argument against this:
TypeScript only protects the code from compile time type mismatches, it does not prevent every other possible kind of error; it does not even protect the code from runtime type mismatches (for example from JSON objects passed in an HTTP or RPC request).
It also does not protect from race conditions, memory leaks, issues with multiple sources of truth, unexpected asynchronous state mutations, poor choice of abstractions, poor encapsulation of state changes, poorly handled runtime exceptions, poorly handled runtime schema validation errors, bidirectional data flow issues (which lead to glitchy state changes and infinite loops), poor choice of ADTs which lead to inefficient code, poor choice of libraries for the use case, misuse of common programming patterns, and any other major logic errors... At best, it projects code from only 5% of all possible bugs; typically the simplest, most obvious kinds of bugs. Please think about this objectively. TS adds value, but very little value and also it takes away value in other ways.
For the really difficult runtime bugs which take serious debug time, it adds no value; it makes debugging harder because of its reliance on source mapping.
And by the way, instead of down-voting, please try to convince me otherwise because I'm really suffering with the new TS-first reality (I'm on the losing side). I really do want to see the light but I'm not seeing it at all.
I'm seeing masses of people running towards a cliff. I know there is a cliff there because I pulled myself out of it (learned the hard way) and have been walking in the opposite direction for the past few years and I don't see why I should go back there simply because that's the direction where all the cool people are heading.
> I've provided you at least 1 robust argument why this is not the case. You've provided 0.
I can share anecdotal data about my own experience while refactoring: I do rely on the type checker (be it Flow or TypeScript) to alert me when my code changes have introduced type errors. Every time I run the type checker I realise that it would have taken me ages to read through my code and hunt down the type mismatches that might have been introduced.
I can also point you to the famous AirBnB's slide, which says that they estimate that around 40% of their bugs can be prevented with TypeScript [0]
> TypeScript ... does not
Sure. It's not perfect. It's not Haskell, or PureScript, or Scala, or OCaml. But it does protect you from some of the errors. Protection from some of the errors is better than no protection at all, that's my opinion.
As a bonus point, type annotations serve as a living documentation of your code.
> instead of down-voting, please try to convince me otherwise
I did not downvote your post. I do not downvote other people's posts.
>> I can share anecdotal data about my own experience while refactoring
I totally understand what you're talking about here. I know that TS feeling of being able to just tell the IDE to rename that variable or type anywhere and have that change automatically applied everywhere in the whole codebase. That said, my anecdotal data (having gone back and forth between first AS2 and AS3 for several years and then later between JS and TS multiple times over many years) is that good tests (especially integration tests) even with modest coverage are equally good at finding these sorts of bugs. If I forgot to rename a variable, my tests will fail straight away.
Also, usually I try to keep my classes and functions localized with well defined responsibilities so that any specific kind of data does not need to traverse too many different files; that makes refactoring a lot easier. IMO, not using TS puts more pressure on me to design code in this way and this design approach yields many other benefits.
It takes encapsulation to another level. For example, I don't even believe in the idea of 'cross-cutting concerns' anymore (which is central to the Dependency Injection pattern). For me, the idea of cross-cutting concerns implies a violation of the separation of concern principle (a violation of the cross-cutting kind to be exact). There are almost always ways to avoid these in your code and doing so is always worth it if the programming environment allows it.
>> I can also point you to the famous AirBnB's slide, which says that they estimate that around 40% of their bugs can be prevented with TypeScript
I did read that article when it came out but my point of view on this is that if mostly the same developers rewrite a project (even if they did so in the same language), I would expect at least 40% to 50% fewer bugs. I don't think TypeScript should get the credit there. The reality is that people learn from their mistakes so if they rewrite something, it's going to be better the next time round.
>> None of those issues are what TS tries to solve. At all.
That is exactly my point.
My argument then follows that that these are in fact the most important issues and that they dwarf all other possible issues; not only in terms of being the most difficult ones to debug but also the most common ones.
My argument is then that the problems which TypeScript does solve are so insignificant in the grand scheme of things that it's simply not worth it.
You do realize that Anders Hejlsberg is on the TypeScript team? I don't want to imply that he's superhuman or anything, but.. just what is your idea of "serious compiler engineers"?
Well maybe he doesn't get enough leeway. Maybe he knows that he should be building an engine from scratch but management won't let him. This is very common in companies of that size.
It is hopefully apparent that the 40% increase (whether it was meant to indicate over leading Javascript engines at the time or over the ActionScript 2 engine) does not in any way indicate there is headroom for a 40% performance increase if static type performance optimizations were applied to a modern Javascript engine.
Many performance improvements come from being able to do code analysis during generation, which is already a trade-off for environments doing in-time interpretation, code generation and optimization.
Large performance increases would most come from removing dynamic language complexity, such as having use of the 'class' feature added in ECMAScript create non-mutable properties by default for function declarations.
I've also seen 20% improvement with TypeScript when working with developers in a big corporate environment (especially when no one cares about the project and everyone gets paid hourly).
But when working with senior developers on open source projects (when people don't get paid), I've seen at least 50% drop in developer velocity using TypeScript and lower code quality.
My theory is that developers who are passionate about coding don't need TypeScript to produce high quality code. It mostly just takes the fun out of it.
But I guess if there is no passion to begin with, then I can see how TypeScript can't hurt in that respect. I've worked for a company like this once for 6 months; I had to quit because I enjoy coding too much to spend most of my time writing and renaming type definitions and waiting for the compiler.
How does having native (as in internally having the transpiler embedded) in deno make you suddenly use TS one day? You can use ts-node.
How long do you think all the browsers would agree that TS would totally be the future of JS and implement it natively, let alone wait until everyone out there to start using such browsers that non TS supporting browsers are almost all eliminated for them to be ignored? There's a reason TS can be compiled down to ES5.
And why are you asking TS for performance over raw JS? Seems off topic from TS' point of view. TS and JS use same principle in the runtime environment and not sure how TS can suddenly beat JS by a good margin.
A project that needs multiple minutes for every change sounds like you're doing it wrong. Split the code or use ts-node?
And you want to throw away all the benefits of TS until all of the above which I don't really feel are required are solved? I don't see why.
Does anybody here know where to go to have conversations with the TypeScript team about adding browser features to better support TypeScript?
A lot was happening back in 2018. A Googler put together a proposal to add ignorable "pluggable" type annotations to JavaScript, which would allow browsers to run TypeScript directly without transpilation (and without type checking). https://github.com/samuelgoto/proposal-pluggable-types
I'm not sure if it's what you mean, but the optional chaining [1] feature added to Javascript (and hence browsers) was championed among others by the TypeScript team.
TypeScript already supports writing type defs as comments in JS files. You get the static checking benefits of TypeScript and can run your code in a browser.
It also has enum support. If someone wants to add enums to EcmaScript, it has nothing to do with TypeScript or their team.
I glad to see this. One of the most painful moment was when writing tests in TS. You will have to deal with countless type errors.
Although @ts-expect-error will partially solve the problem, what I have learned is don't write tests in TS - you should test it in the real runtime environment where there is no type checking.
The biggest thing killing me right now with TypeScript is more of a general ecosystem issue. That issue being how TypeScript interacts with the concept of "workspaces" and Yarn's Plug'N'Play system. I use TypeScript with ts-node pretty heavily. I'm also trying to use a shared source package outside the root workspace file hierarchy :/
97 comments
[ 2.7 ms ] story [ 145 ms ] threadThis article mentions material-ui and styled-components. My experience with typescript has been cumbersome with these libraries. A lot of time is spent figuring out what ”types” to return. I find this very difficult in most cases and not fun at all.
I figure there must be something wrong in my approach or in my ts config (no explicit any).
In short. How to best handle styled-components/material-ui/other library in ts environment? Or is typescript just to much overhead in these usecases?
The main issue I've had with these libraries and typescript is compiler/IDE performance, which 3.9 seems to suggest improvements.
I'm not quiet sure what issues you are facing without some examples. Given you are listing react libraries, the react community discord server might be a good place to ask specific questions. They have library and typescript specific channels to ask beginner questions in:
https://www.reactiflux.com/
Just to follow up what I meant i created a quick gist. Not working code but maybe can explain it a bit better.
What I mean as an example is this. I create a function that uses styled-components. I have no idea what the return type should be at first. I must dig into internals of styled-components and eventually find something like "AnyStyledComponent" which is basically the same as "Any" but for styled-components.
https://gist.github.com/slackday/7142251cf2bb3660f8c24492aa1...
This is just one example. Just curious. Not to pick at either Typescript or styled-components which are both great!
If there’s not I recommend disabling your linter for the line and adding an entry in .d.ts. You lose effectiveness but it still works.
I’m using Blueprint 3 in TS environment and it’s really nice to get feedback about, say, wrong props passed to one of its styled components right as you type.
> My experience with typescript has been cumbersome with these libraries. A lot of time is spent figuring out what ”types” to return. I find this very difficult in most cases and not fun at all.
Whether your code is statically typed or not, you generally have to be aware of which data structure goes where—otherwise it’s easy to break things.
When code is statically typed, most things break at compile time, enabling your IDE to give immediate feedback. I find the flow much more pleasant if I don’t have to hunt down runtime errors resulting from using a library (BP3 or anything else) in a wrong way.
There is some upfront effort in specifying types explicitly where compiler can’t figure it out or does so mistakenly; how fun that is might depend on your personality and established habits. In addition, I believe it heavily depends on tooling—I like using TS in VS Code environment, but TS with Vim (which I’ve been using for many years) was somewhat of a hell.
Once in a while I come across an obscure library without TS typings, in which case I would generally provide a `.d.ts` file for it, starting with a catch-all `any` type for its exports, later potentially specifying it further if useful and feasible. This is by far the least fun part.
I wasn't aware of the `.d.ts` files. It sounds a lot like what I was looking for! Thanks again for your feedback and help :-)
By the way, keep in mind that it is often unnecessary to specify types explicitly because TS can infer them from context. I used to specify way too many types when I was initially learning TS.
If you have time, I have a question. Note that my professional exposure to Typescript projects is minimal.
I've built a Javascript library which lives in GitHub, NPM, etc (I won't spam the link). It is entirely module-based Javascript.
My understanding is that while Typescript-based projects can use non-TS JS libraries (because TS is a superset of JS), using that library would require more work - initial code, and maintenance - than using an equivalent library either written in TS, or one that includes a TS Declaration File.
If yes to the above, then - given that I'm serious about my library and want other people to use it if it meets their project needs - I assume I need to write a .d.ts Declaration File (or maybe several?) for it.
- How much initial work are we talking here: weeks? Months?
- After the initial work, how much additional work is required to maintain the .d.ts files(s)?
- How much damage could a poorly written .d.ts file do to a library?
- I've seen the Microsoft documentation[1] and ... this looks like a massive amount of work for my library. I know how popular and useful TS has become but, at the end of the day, would I be wasting my time doing what would be, for me, unpaid work?
[1] https://www.typescriptlang.org/docs/handbook/declaration-fil...
> My understanding is that while Typescript-based projects can use non-TS JS libraries (because TS is a superset of JS), using that library would require more work - initial code, and maintenance - than using an equivalent library either written in TS, or one that includes a TS Declaration File.
More work, yes, but often not a lot of it depending on need. (You can just tell Typescript some modules are `any` and treat them as a black box.)
It's not so much "more work" as it is "less confidence". If you are looking for trust from TS developers in your library, a TS Declaration is API documentation directly in their IDE that does basic sanity/usage checks for them.
> How much initial work are we talking here: weeks? Months?
I find it is usually in the order of hours. The variables are the size of your library and in particular its external API surface and how well your API is already documented. A .d.ts file is just another sort of API documentation. If you've got good JSDOC comments, for instance, that does a lot of the work already. In some cases you can get a .d.ts file for "free" from Typescript if you follow a couple patterns in your JSDOC comments and run Typescript on your JS files. (It might also give you errors where your code doesn't agree with type hints in your JSDOC comments, which you may or may not find useful to discover potential bugs or edge cases in your code.)
> After the initial work, how much additional work is required to maintain the .d.ts files(s)?
It depends on your API changes, especially breaking changes. I've told a number of projects to feel free to @ me when they make API changes and I'll PR a .d.ts update and it's rarely more than a couple minutes to look at what their breaking API changes are and what update what needs to be updated.
> How much damage could a poorly written .d.ts file do to a library?
Again, it's mostly a "loss of confidence" style issue. A poorly written .d.ts isn't going to stop a Typescript user from using your library, it's mostly at worst just going to get in their way and they have to use an escape valve (such as a cast to `any` telling Typescript to get out of the way) and it is no worse than having no .d.ts.
Again, if it helps to think of it as API documentation: a bad .d.ts file is like finding an out of date API document for an old version of the API. It can still offer sign posts to what the expected API is supposed to be, it just requires the user of the library to distrust that documentation and either read the source directly or find other documentation sources (StackOverflow or example code from other users, for example).
> I've seen the Microsoft documentation[1] and ... this looks like a massive amount of work for my library. I know how popular and useful TS has become but, at the end of the day, would I be wasting my time doing what would be, for me, unpaid work?
As with any open source work it is a trade-off and you need to make that determination based on what you are comfortable with maintaining. That's why whenever I've written .d.ts files for libraries I don't maintain, I make sure to explain the maintenance effort, often volunteer to try to do my best to keep it maintained, and also realize and respect that not every library wants to maintain their own .d.ts.
It's also why you don't necessarily need to build the types yourself if you aren't (yet) comfortable learning Typescript or switching to Typescript. (Aside: I find that curiosity in adding your own .d.ts file is often a baby step for learning where Typescript helps you in making a better library, and some of the projects I first helped maintained a .d.ts eventually learned and switched to Typescript themselves.)
If you can find a user of your library that uses Typescript, they may already have a partial type definition you can start from and/or be willing to help...
The other thing I'd recommend is if your focus really is just specifically on writing .d.ts files, and you aren't expecting to use more Typescript directly yourself: get more familiar with and start regularly using JSDoc comments. Typescript in JS mode already understands and can do a lot with JSDoc comments. As I mentioned, it will sometimes give you a fully formed .d.ts if you ask and you have enough JSDoc comments, you'll even get the advantage of some of its type analysis in your project (not as much as if you were writing Typescript directly, but more than just a linter will do). If you use an editor such as VSCode where the JS experience is already backed by the Typescript language service you'd start to see some things almost Typescript-like light up in your development experience as you add more JSDoc comments (maybe even to help explain why you might want to use more Typescript directly).
https://en.wikipedia.org/wiki/JSDoc
Thank you! This is a fantastic response (now bookmarked).
I think it best not to do the work now - the library is still evolving and keeping the basic documentation up-to-date (inline comments, but not in JSDOC format) is already an overhead. But this is something I'll need to address at some point. I'll add it to the library's roadmap.
To generate typings for your library, you can start with converting from jsdoc if you have docstrings with types, or if you want to infer types at runtime during a testing suite you can use something like https://github.com/microsoft/dts-gen
I've never used dts Gen but it looks promising as a starting point. But as an additional point, only the public functions and classes really need type declarations, so unless you export all of your functions that could cut down on the burden to write up the types.
Typescript infers return types, so even if you don't write out a return type, it will still be fully typed.
If you still want to specify the return type, you can take advantage of IDE support. Write the function without an explicit return type, then you can hover over it to see the inferred type, then copy the type.
In my preferred IDE (PyCharm), it's even easier since there's a lightbulb action for it. Alt+Enter > "Specify return type explicitly" > Enter
There are Javascript patterns that just don't type well. There are other ways to write your code that will be easier to fit into the type system. It might be more verbose and less reusable at times, but it ends up being a worthwhile tradeoff.
That's general advise and might not apply to the libraries you mention, but it's worked well for us to explicitly call out the differences.
For example, using thunks, one can pass actions directly, or functions that resolve to an action. So, when you're chaining them, it becomes fiddly with types. Compiler complaining about some type or just resolving to any type. I've spent quite some time on that one. Similarly with Formik, I wanted to have generic validators and generic way of applying those validators ... another one that cost me hours to get through and I wasn't satisfied with the result.
There is a lot of information around about Typescript, also various guides like the one here: https://github.com/piotrwitek/react-redux-typescript-guide
But in the end I've felt that while I've become somewhat proficient with Typescript, I was still quite slow to pump out screens and features. And honestly, I didn't enjoy working with it.
(Then there is another can of worms, which is dpendencies and their typings, where it happened that some minor version was bumped and it broke the typings of another library that depended on previous one. So, you might ask, why don't you just pin the dependencies that work together? Well, sometimes an important bug is fixed in a library and you want to upgrade, but you can't, because a person unrelated to library maintainer that handles typings hasn't upgraded them yet ...)
It's probably a good idea to learn how to use generics (type parameters) effectively. For me, it helped immensely to think of them as basically declarative functions in the type system, with the generic/type parameter being just like a function parameter. The cool thing is that while you have to declare them on a function, a lot of times they can be inferred at the call site. With higher level abstractions, most of the time the types just flow through these generics and you get what you want at the other side just based on inference.
[0] https://redux-toolkit.js.org
[1] https://redux.js.org/recipes/usage-with-typescript
[2] https://react-redux.js.org/using-react-redux/static-typing
[3] https://redux-toolkit.js.org/usage/usage-with-typescript
This is a heretic/unpopular opinion, but I think especially for existing JS/React projects, the laxest possible TS setting is the way to go.
You should be able to get to no type errors in your existing JS project with not too many changes. In these contexts (existing projects) I like to think of TS as more editor experience support than seperate language. Modern React is very friendly to TS automatic type inference, so IMHO you should be getting decent benefits from typescript without annotating anything at all. And instead of fixing complicated type errors for no real gain, just // @ts-ignore and move on.
I don't know what your specific issue is with styled-components. Should work pretty much out of the box? My suggestion would be to use CSS objects over string literals because that way you get typechecking for your CSS.
Not sure why you think it's "heretic/unpopular", but I think it's the only reasonable way to incrementally migrate an existing codebase to TypeScript.
Definitely agree with you about the IDE experience, just that alone is enough for me to justify the transition.
The company must pay someone to do the cleanup. Otherwise, of course it won’t work.
https://react-typescript-cheatsheet.netlify.app is a super detailed guide to exactly this, complete with worked examples for lots of common cases.
Styled Components has a specific section in the docs on using SC with TypeScript, which might be useful too: https://styled-components.com/docs/api#typescript
However coming from languages where types are a first element of the language (c++, rust, go...), I often miss a lot of features in typescript (e.g. type conversion overload, generic specialization, etc...)
I know that by design Typescript doesn't want those features and I understand the rationale behind it. I'm just wondering if I'm the only one in that case and if someone would know a language transpiling (not compiling) to JS more appropriate to my tastes (and hence with different goals).
Elm/Purescript syntaxes are not my kink. Open to other suggestions though.
What's your definition of transpiling and what are you looking for?
* I personally find the difference meaningless, lots of languages use intermediate compilation targets like C or JS or LLVM IR or assembly so transpiling and compiling mean the same thing to me
https://blog.logrocket.com/what-is-deno/
Just adding as it might interest someone :)
For js, specifically : https://haxe.org/manual/target-javascript.html
Coincidentally, Haxe Foundation announced a new version here today : https://haxe.org/blog/haxe-4.1.0-release/
(disclosure : member of Haxe compiler team)
Types absolutely are a first class citizen in TypeScript. Especially coming from Go, which doesn't even support generics, Typescript is really quite powerful. It even has support for ADTs via discriminated unions, which gives you the same power of enums with associated types that you'd get in Rust/Swift.
Is it possible the reason you feel like Typescript doesn't have Types as a first class citizen is because it leverages structural typing rather than nominal typing?
This shows clearly why the language server protocol is such a bad design decision and so broken — every language has to implement it itself, and there are no shared features or functionality across languages.
Coming from IDEA, where the exact same refactoring functionality and features work no matter if using typescript, kotlin, Rust, C#, golang or dart, exactly identical in all ways, this has been a huge issue for myself.
Languages Servers should just expose a clean standardized AST format, representing standardized nodes, and this should in turn allow the IDE to act upon this (which would immediately be represented in changed source).
IDEA does a lot of language specific stuff, it just unifies the UX. Which is what language servers aim anyway.
BTW, I'm a long term user of powerline-go. Fantastic piece of software!
Yeah, but with IDEA I have the exact same functionality for Rust, Typescript or Java, while the language servers will never agree on the exact same functions being called the same and doing exactly the same. It means relearning your editor every time you switch your language.
I realize I’m probably in the minority as a person who writes basically every project in another language, whichever happens to work best for the project, while most others probably use only a few languages for most of their career, but it’s still annoying.
On top of that most LSP implementations are open source which lowers the cost of entry for developers and avoids lock-in with proprietary IDE's. And the well specified network protocol makes it much more flexible to different dev setups (e.g. run the LSP on more powerful cloud/remote hardware for large apps, use it with docker-based development setups, etc).
So I would argue the exact opposite, the model of proprietary IDE's building walled gardens around so much useful developer tooling for otherwise open-source languages and ecosystems, is what is broken.
Every editor works the same now — but every language completely different. A user writing JS in vim can write it the same way in VSCode or Atom, but a user using Atom to write JS can’t write Rust in Atom the same way.
I’d love to see a different LSP protocol, one where the LSP exposes much more information, and the editor implements the functionality on top of that, so every language works the same.
But to your point, LSP have brought the IDE experience to others programming editors. Ex: Emacs now can do everything VSCode does for JS because of LSP.
- Native TypeScript runtime interpreter in Deno (TypeScript alternative to Node.js).
- Native TypeScript runtime interpreter in all major browsers.
- At least 20% performance improvement over plain JavaScript.
The build step has to go away because:
- Source maps are unreliable, bulky, slow and add too much complexity for some environments; many environments fail at using them correctly and this can make it difficult to debug code. Being forced to debug ugly transpiled JavaScript is unacceptable and should never happen.
- It's slow to work with. TypeScript often claims to be 'scalable' but reality is that large projects often take multiple minutes to build for every change. There are no good incremental build solutions which also do proper type checking. There is no runtime type checking.
Native browser support is also essential. The bundling step makes in infeasible to freely mix and match modules written in the two languages in a way which is debuggable.
Microsoft should look into Adobe Flash's ActionScript 3 migration from ActionScript 2 for inspiration (both based on ECMAScript spec BTW, just like JavaScript/TypeScript). I remember ActionScript 3 clearly because it was able to deliver a 40% speedup AND runtime type checking...
In spite of these huge benefits, I remember that some developers were still hesitant to switch to ActionScript 3! This new generation of developers has clearly lost its ability for critical thinking - I find the current complete lack of resistance to TS is very strange.
There are a lot more reasons to resist JS to TS migration compared to AS2 to AS3 migration.
I remember in AS2, most people were not declaring types in their code (even though there was support for compile-time type checking). Only in AS3 people started adding Type annotations to their code.
That doesn't make sense. Browsers are unlikely to add native typescript support in the foreseeable future; whereas meanwhile typescript offers huge benefits compared to untyped javascript when it comes to large codebases and refactorings.
It's not my fault that browsers are not going to do it. It doesn't change the fact that it is necessary and that TS is useless without it (the cons outweigh the pros).
>> huge benefits compared to untyped javascript when it comes to large codebases and refactorings
I've provided you at least 1 robust argument why this is not the case. You've provided 0.
I can provide another argument against this:
TypeScript only protects the code from compile time type mismatches, it does not prevent every other possible kind of error; it does not even protect the code from runtime type mismatches (for example from JSON objects passed in an HTTP or RPC request).
It also does not protect from race conditions, memory leaks, issues with multiple sources of truth, unexpected asynchronous state mutations, poor choice of abstractions, poor encapsulation of state changes, poorly handled runtime exceptions, poorly handled runtime schema validation errors, bidirectional data flow issues (which lead to glitchy state changes and infinite loops), poor choice of ADTs which lead to inefficient code, poor choice of libraries for the use case, misuse of common programming patterns, and any other major logic errors... At best, it projects code from only 5% of all possible bugs; typically the simplest, most obvious kinds of bugs. Please think about this objectively. TS adds value, but very little value and also it takes away value in other ways.
For the really difficult runtime bugs which take serious debug time, it adds no value; it makes debugging harder because of its reliance on source mapping.
And by the way, instead of down-voting, please try to convince me otherwise because I'm really suffering with the new TS-first reality (I'm on the losing side). I really do want to see the light but I'm not seeing it at all.
I'm seeing masses of people running towards a cliff. I know there is a cliff there because I pulled myself out of it (learned the hard way) and have been walking in the opposite direction for the past few years and I don't see why I should go back there simply because that's the direction where all the cool people are heading.
I can share anecdotal data about my own experience while refactoring: I do rely on the type checker (be it Flow or TypeScript) to alert me when my code changes have introduced type errors. Every time I run the type checker I realise that it would have taken me ages to read through my code and hunt down the type mismatches that might have been introduced.
I can also point you to the famous AirBnB's slide, which says that they estimate that around 40% of their bugs can be prevented with TypeScript [0]
> TypeScript ... does not
Sure. It's not perfect. It's not Haskell, or PureScript, or Scala, or OCaml. But it does protect you from some of the errors. Protection from some of the errors is better than no protection at all, that's my opinion.
As a bonus point, type annotations serve as a living documentation of your code.
> instead of down-voting, please try to convince me otherwise
I did not downvote your post. I do not downvote other people's posts.
[0] - https://twitter.com/remohjansen/status/1093815648566894594?l...
I totally understand what you're talking about here. I know that TS feeling of being able to just tell the IDE to rename that variable or type anywhere and have that change automatically applied everywhere in the whole codebase. That said, my anecdotal data (having gone back and forth between first AS2 and AS3 for several years and then later between JS and TS multiple times over many years) is that good tests (especially integration tests) even with modest coverage are equally good at finding these sorts of bugs. If I forgot to rename a variable, my tests will fail straight away.
Also, usually I try to keep my classes and functions localized with well defined responsibilities so that any specific kind of data does not need to traverse too many different files; that makes refactoring a lot easier. IMO, not using TS puts more pressure on me to design code in this way and this design approach yields many other benefits.
It takes encapsulation to another level. For example, I don't even believe in the idea of 'cross-cutting concerns' anymore (which is central to the Dependency Injection pattern). For me, the idea of cross-cutting concerns implies a violation of the separation of concern principle (a violation of the cross-cutting kind to be exact). There are almost always ways to avoid these in your code and doing so is always worth it if the programming environment allows it.
>> I can also point you to the famous AirBnB's slide, which says that they estimate that around 40% of their bugs can be prevented with TypeScript
I did read that article when it came out but my point of view on this is that if mostly the same developers rewrite a project (even if they did so in the same language), I would expect at least 40% to 50% fewer bugs. I don't think TypeScript should get the credit there. The reality is that people learn from their mistakes so if they rewrite something, it's going to be better the next time round.
Compile-time checking is well worth the switch. Refactoring old JS express apps is a nightmare.
You can add TS incrementally, so your argument about "downsides" is not valid. You can use it as strictly as you'd like.
That is exactly my point.
My argument then follows that that these are in fact the most important issues and that they dwarf all other possible issues; not only in terms of being the most difficult ones to debug but also the most common ones.
My argument is then that the problems which TypeScript does solve are so insignificant in the grand scheme of things that it's simply not worth it.
Like putting lipstick on a pig.
How would that work? TS is not an optimizing compiler, it's only a type checker.
The fact that Microsoft does not want to hire serious compiler engineers and prefers to spend all the money on marketing is not my fault.
Many performance improvements come from being able to do code analysis during generation, which is already a trade-off for environments doing in-time interpretation, code generation and optimization.
Large performance increases would most come from removing dynamic language complexity, such as having use of the 'class' feature added in ECMAScript create non-mutable properties by default for function declarations.
But when working with senior developers on open source projects (when people don't get paid), I've seen at least 50% drop in developer velocity using TypeScript and lower code quality.
My theory is that developers who are passionate about coding don't need TypeScript to produce high quality code. It mostly just takes the fun out of it.
But I guess if there is no passion to begin with, then I can see how TypeScript can't hurt in that respect. I've worked for a company like this once for 6 months; I had to quit because I enjoy coding too much to spend most of my time writing and renaming type definitions and waiting for the compiler.
More like: Imagine being passionate enough about something to complain about it online, while not even bothering to think it through.
How does having native (as in internally having the transpiler embedded) in deno make you suddenly use TS one day? You can use ts-node.
How long do you think all the browsers would agree that TS would totally be the future of JS and implement it natively, let alone wait until everyone out there to start using such browsers that non TS supporting browsers are almost all eliminated for them to be ignored? There's a reason TS can be compiled down to ES5.
And why are you asking TS for performance over raw JS? Seems off topic from TS' point of view. TS and JS use same principle in the runtime environment and not sure how TS can suddenly beat JS by a good margin.
A project that needs multiple minutes for every change sounds like you're doing it wrong. Split the code or use ts-node?
And you want to throw away all the benefits of TS until all of the above which I don't really feel are required are solved? I don't see why.
A lot was happening back in 2018. A Googler put together a proposal to add ignorable "pluggable" type annotations to JavaScript, which would allow browsers to run TypeScript directly without transpilation (and without type checking). https://github.com/samuelgoto/proposal-pluggable-types
And a member of the TypeScript team at Microsoft put together a proposal to add enums to JS. https://github.com/rbuckton/proposal-enum
Neither one of these seem to be active. What happened? What would it be like to get these landed?
[1] https://github.com/tc39/proposal-optional-chaining
It also has enum support. If someone wants to add enums to EcmaScript, it has nothing to do with TypeScript or their team.
I glad to see this. One of the most painful moment was when writing tests in TS. You will have to deal with countless type errors.
Although @ts-expect-error will partially solve the problem, what I have learned is don't write tests in TS - you should test it in the real runtime environment where there is no type checking.