My issues with it are that it's just an extremely verbose language. Just like all Microsoft languages. All the while lacking advanced type system features like algebraic data types, pattern matching etc.
My issues with it are that it's just an extremely verbose language. Just like all Microsoft languages. All the while lacking advanced type system features like algebraic data types, pattern matching etc.
You have discriminated unions and the compiler is clever about them, so you can implement ADTs if you want them with a little but not a nasty level of boilerplate. (They can also be implemented with an abstract class if that's more your bag.)
It lacks pattern matching because it intentionally doesn't include a runtime component, which I think is also wise. Options exist if you want to use them. I've seen people use Purify to good effect.
However, coming from a truly terse language like Haskell you'll just feel TS is too verbose and not very elegant. TS is the most verbose and least elegant of the languages I'm personally using, on par with Dart.
ADTs not only feel dirty because they're not first class citizens (you build them with the TS primitives by adding a discriminating union key) but also somewhat useless since you don't have pattern matching.
Although pattern matching would not be a trivial problem to solve in TS. It could be solved with the compiler, however, you'd still have to hack the compiler API quite a bit too and TS doesn't even support integrating custom extensions with a config file like Babel does.
Btw thanks for pointing me to that ts-purify, it looks good!
I'd really disagree with the notion that discriminated unions/ADTs are useless; the compiler is clever and will constrain the type in an `if` or a `switch` (particularly useful with an enum type, too). I use this regularly and it's really effective; my `nestjs-auth` library makes it more or less a requirement and its users seem to really dig it. And if you do it as an abstract class instead of a key, you can use polymorphism to take care of a lot of what would otherwise be pretty clunky--this is how you can make a solid maybe/option type in the vein of Scala.
I guess my problem with TS ADTs is just that they're done with the TS primitives whereas they could be true first class citizens. But such a feature may be too hard to swallow for your typical JS developer whose first introduction to types is Typescript.
Btw can you elaborate on that Enum with ADTs? Or did you mean that you use Enums with switch-case? I use it too and find it one of the best bits of TS.
The thing about making ADTs first-class citizens means that TypeScript stops being JavaScript, and one of the most valuable parts of TypeScript to me is that I can just look at it and know what the underlying JavaScript is. I kind of equate it to writing C on an old platform--it's going to be munged significantly but at a glance you can have a high degree of confidence that the code coming out the other end is going to be what you expect it to be.
I also think Typescript makes the right tradeoffs, yes it may not have a Haskell-level type system, but in return, it has amazing integration with JS code and existing libraries, and no runtime.
As a side note, coming from someone whose previous exposure to type systems was Java and Kotlin, Typescript seems to have a pretty powerful type system. Yes, it may not have some/many Haskell-level features but I question whether those would have been necessary in the first place. At some point a more rigorous type system must stop generating value, otherwise we would all be using coq.
For reference, here's the home page and documentation for purify-ts.
Furthermore, where possible (variable assignment, function returns) types are inferred, and do not need to be specified at all, leaving you with mostly plain JS syntax.
Besides that, no type signatures without parameters and other things just produce a lot more code than you'd have in a nicer type system.