Rescript/reasonml is still in development, and a more seasoned dev team can easily pick it as an better alternative to typescript.
Its a bummer haxe did not promote itself more for the web, as its a amazinlgy good piece of tech. The languge shows age, but has an awesome typesystem and metaprogramming capabilities.
Its quite rare to see interop between compile to js languages tho. Also rare to see projects using more (if not in the middle of a rewrite/port) than one compile to js language. YMMV.
> Its quite rare to see interop between compile to js languages tho
js interop in Clojurescript is dead simple. Moreover, you can have shared logic between different runtimes. The promise of Nodejs for code re-use, in practice turned out to be not as straightforward, even though you have js runtime in both places. With Clojurescript, you can have the shared logic in the same namespace - it's mindblowing, you can have functions that work on both - JVM and JS.
Im not talking about X->JS->X interop, but X->Y->JS->Y->X interop, where X,Y = compile to JS language.
> it's mindblowing, you can have functions that work on both - JVM and JS
Thats basically what you could do long before Nodejs (that made server/client code sharing popular) came out in Haxe. You could target a huge number of targets from a single codebase.
Are you saying that getting two different compile-to-JS languages to interoperate is messy and you have to go through multiple transpilation layers to make them talk to each other?
The Clojurescript way isn't about transpiling between different compile-to-JS languages. It's simpler: write once in Clojure, compile to both JVM and JS directly. No intermediate language chains needed. And you are free to use whatever js and java libs directly.
Yes, sure - valid point about Haxe, you're right, it actually did this before Clojurescript or even before Node existed. IIRC Haxe could compile a single codebase to multiple targets. That multi-target approach tho required writing in a lowest-common-denominator lang. Cljs practical in the sense that you get the full power of Clojure on the JVM side and reasonable JS semantics on front-end - without compromise. Haxe often meant sacrificing language features to stay compatible across all targets.
Clojurescript is surprisingly pragmatic in that sense and works well. The downside - you can use Cljs on its own, but it truly shines when paired with Clojure, but JVM, despite being amazing piece of tech has a marketing problem - people hear JVM and immediately think Java.
This is some criticism that lacks any depth or insight.
I've deployed projects in Elm, Scala, Clojure, Purescript and TypeScript has many great qualities that the others don't have.
It's an incredibly powerful language with a great type system which requires some effort in understanding, (e.g. 99% of candidates don't even know what a mapped type is, it's written in the docs...) and minimal discipline to not fall in the js pitfalls.
On top of that you have access to tons of tools and libraries, which alternative ecosystems either don't have (e.g. no compile-to-js language) or have to interoperate with at js level (anything from Reason to Gleam) anyway.
Beyond that, there's other important considerations in choosing a language beyond its syntax/semantics and ecosystem, such as hiring or even AI-friendliness.
Stricter TS is absolutely a valuable effort to chase.
The issue with TS is that its way too easy to fallback to unsafe code. Also the TS typesystem is WAY, WAY too complex. They pile new hard to grasp niche features that has made it really hard to grasp.
The TS sweetspot was (imho) somewhere around 1.8-2.0 era. These days you can run doom in the typesystem.
I cant say about hiring, as i dont hire a dev that knows language X, i hire engineers that know the ins and outs of how software should be written, and know when to pick Go, when to pick ocaml and when to go with C/Rust.
Also i would never use 99.9% of npm packages (js or ts) so i dont really care that much.
As an example writing typeheads for reasonml is not really that hard, as a benefit you know exactly what parts you use.
Also i dont use AI, and we dont accept any PR that are videcoded.
It's not that easy to fall to unsafe code if you know what you're doing, do not have typescript skill issues and use the right libraries, such as fp-ts or effect-ts (an evolution of Scala's ZIO on TypeScript).
Those ecosystems are huge by the way, effect is still very niche-y due to its usage of functional programming and effect systems, niche in a sense, it gets more downloads than Angular.
I have my beefs with TypeScript's complexity, verbosity and limits, don't get me wrong but I don't see any realistic alternative for who wants to write type safe code.
I loved Elm or Reason, but they are not realistic nor productive choices unless your IT team has North American startup budget.
In my real world, we don't have the budgets to lure the kind of brilliant engineers that know when to pick Ocaml and when to go with Rust (or have ever used any of them).
I get the idea of libraries like fp-ts and effect-ts, but like most libraries in this area, they are just boltons. I dont like to write unidiomatic code for given language if it is not designed for it. This means if i wrote a applicative that must satisfy homomorphism in javascript:
APP.ap(APP.of(ab), APP.of(a)) = APP.of(ab(a))
Im pretty sure not a single dev would understand what the hell is going on, and i would have to buy quite a few beers to get that passed in a CR.
I write idiomatic code for the language:
Eg. In Go i loop and use mutability when its the correct thing to do, but in OCaml i almost exclusively use recursion and favour a monadic api, and javascript being a middle-ground i tend to just just the builtins map/filter/reduce and pals for most things. I dont need a monad for the sake of it.
That said i tend to step out of this rule when it comes to errors, and avoid throwing as much as possible. Errors as values is invaluable.
> Im pretty sure not a single dev would understand what the hell is going on, and i would have to buy quite a few beers to get that passed in a CR.
That's a questionable example imho, for few reasons.
The first is that understanding an applicative functor requires you to first understand map, apply and lift.
Starting from an applicative, in any language, including Haskell, is like starting from a monad, (as you know very well they are almost the same thing as a monad is an applicative with one more rule) and then it's quite clear why we get endless blog posts that leave you no brighter.
The second is that we're talking about TypeScript, not JavaScript.
Let's make an example.
Given a definition for map in TypeScript:
map: <A, B>(f: (a: A) => B) => ((fa: F<A>) => F<B>)
which requires a minimal typescript understanding (a function from A to B and a value of type F<A> you get F<B>) to read.
If you can read map you can read ap in TypeScript:
If i need something that must be proven correct. Something that really cant (ungracefully) fail, where there is no null pointer exceptions, or other panics (eg rust has unwrap, and Go has nills).
Something that does not need to run on C speeds (both Go and OCaml have similar performance, somewhere around 80-90% of C/Rust give or take), and when i want to have a fast feedback cycle (the OCaml compiler is even faster than Go's compiler).
Basically OCaml when i want to have a good sleep at night, and be sure im not paged at 2AM for some weird panic or null pointer error.
Thats why i glue stuff together, i might have some "this-is-critical-as-fuck" code written in OCaml, and a webserver written in Go, and some perf critical feature written in Rust/C.
It all depends on the requirements. Its a shame devs shy away from that, and use their only tool (language) for all things, leading to more brittle and overcomplex software.
This is the same _type_ of elitism that I've seen from the Scala community and really makes TS seem unpalatable. Big "A monad is just a monoid in the category of endofunctors" vibes.
Yeah, I'm quite sure inverting trees is more relevant to real world programming than knowing the fundamentals of a type system people say they are expert in. /s
In any case, I am against technical interviews and never ask any technical questions beyond just general talk of how people like to work, and their previous projects.
But I know for a fact the overwhelming majority of people that say they know TypeScript don't know a tenth of what's written in the docs, and mapped types were just a very basic example.
It is also how C++ and Objective-C got users from C land.
The examples on the JVM and CLR got it through, targeting the same bytecode, and Swift even if imposed from above, also had to make interop with Objective-C first class, and is now in the process to do the same for C++.
Turns out adoption is really hard, if a full rewrite is asked for, unless someone gets to pay for those rewrites, or gets to earn some claim to fame, like in the RIG and RIR stuff.