That’s all right! But the DX of editor of ts is very ergonomic, which keeps me using ts all over the time.
I slightly disagree. It’s not about what you can do but how you can do it.
In my opinion, FP-influenced languages make code more aesthetic. Features help reduce code nestings, amount of parenthesis, magic strings, and “point-full” programming. They help to focus on data flow rather than writing code itself.
You could do a lot and probably be even more efficient (performance-wise) with writing WebAssembly by hand (reducing the bloat generated by the backend), but it’s extremely impractical.
The syntax can be your friend with particular programming concepts or your foe.
You can do a lot of programming with FP flavor with JS & TS but languages itself will be your foe because of their syntax.
JS & TS lacks particular things in their syntax:
-
blocks of codes are not expressions
-
lack of real pattern matching (and I’m not only talking about ergonomics of switch-case, but it’s also about destructing and doing additional checks)
-
lack of variant/enums support
this:
type Test1 = {
type: "test1",
value: number
}
type Test2 = {
type: "test2"
}
type Test3 = {
type: "test3"
value: Error
}
type Test4 = {
type: "test4"
value: string
}
type MyTest = Test1 | Test2 | Test3 | Test4;
is not even close to this:
type myTest =
| Test1(int)
| Test2
| Test3(result<string, string>)
| Test4(string)
It might look trivial but it flips how code is developed in practice.
Less code = easier maintenance + less bugs
-
inheritance
Something that I missed so much at the beginning of my journey with Rescritp & Rust. But in practice with large legacy code bases, it’s an enormous pain to track the path of inheritance in extended interfaces (especially in TS with its picks and omits).
In general, code organized in modules is more available than nested in types/interfaces/classes -
null/undefined/error handling
pattern matching a result is far more intuitive than try catching and less error-prone, but it can be done well only with other syntax features like proper variant support, proper pattern matching, proper tuples, code blocks as expressions, and so on… -
(TS only) typescript theoretically supports tuples but the syntax is almost identical with arrays which causes a lot of trouble
The problem with additional libraries for TS is significant, and it’s not about adding and configuring libraries.
It’s about:
- maintenance (updating versions in large code bases)
- consistency (for large teams that often change it’s a challenge to keep rules consistent)
I loved fp-ts
& karma
but implementing it well with a large team is tough.
Languages like Rescript or Rust did things in an opinionated way and got credit for that.
Languages like Javascript(and Typescript) want to be everything and you can be sure that if something wrong can be done, some developers in your team will do it.
That is the reason why i keep using rescript. The biggest problem i think in rescript is the ide support, especially in native Windows environment.
The biggest pain is that TS has no idea of how to type a tuple unless you provide a type annotation.
const t1 = [1, "a"] // type is Array<string | number>
// you have to do this
const t1: [number, string] = [1, "a"]
For me it’s all about the quality of the type system (and ML languages do very well here):
- Type soundness (there seems little point to a type system without it).
- Hindley-Milner type inference
- ADT’s, / Variants together with pattern matching for better data modelling
That’s the key language features, for tooling etc… it’s
- Compiler speed
- True js alternative, (eg… use of js ecosystem)
Things I’m not so keen on.
- Higher level module system - there are likely better alternatives for the features it provides.
- PPX’s - better alternative’s