
TypeScript vs. ReasonML - jasim
https://blog.dubenko.dev/typescript-vs-reason/
======
pkilgore
I'm building a project in ReasonML right now with reason-react. The Reason-
only parts are actually a joy. The problem is interop with the wider
ecosystem, and bucklescript.

They are serious problems. You end up writing a ton of [@bs.... ] annotations
to get things to work together that ultimately ___result in runtime errors_
__.

I hate battling a compiler (with sometimes quite cryptic errors, particularly
identifying syntax errors) only to find that I can't actually free myself from
the same type of errors I'd see with regular old JavaScript.

I can dig through my discord history and give more specifics. But given the
massive learning curve and poor tooling that exists these days it's a step
backwards from mainstream production JS development.

That said, the community has really got some wonderful folks out there, and is
very helpful. I hope they can figure out interop with basic JS like promises.
And tooling. And let me use async/await. And make bundle splitting easier to
implement.

~~~
deathtrader666
You could write your app using the Elm-inspired Bucklescript-TEA [0] framework
in OCaml, and use js_of_ocaml to transpile OCaml into JavaScript.

[0] - [https://github.com/OvermindDL1/bucklescript-
tea](https://github.com/OvermindDL1/bucklescript-tea)

~~~
pkilgore
In what ways does it fix my major issues with bucklescript (simple interop
with JS libraries / object / output, promises, async/await being highest on
the list).

~~~
deathtrader666
With js_of_ocaml, you need not use Bucklescript at all.

Both are transpilers for OCaml -> JavaScript.

------
grumpy8
IMHO the biggest reason to use TypeScript rather than Reason is because, in
the end, it's still javascript and it stays within the same ecosystem. As
great as Reason is, it's adding too many dependencies. The only time I'd go
with Reason instead of Typescript is if the developers on the team are already
proficient with OCaml. It's going back to the "Use boring technologies even
though some things suck as it's better to deal with known issues than unknown
issues; the grass isn't always greener with new technologies, just different
things that suck".

~~~
StreamBright
>> in the end, it's still javascript

This is exactly the reason I prefer Reason. :)

~~~
gridlockd
ReasonML is also just Javascript in the end, dealing with the same platform
limitations.

~~~
dymk
This is like saying Rust is just x86 assembler

~~~
wvenable
The more high-level the target, the more that target bleeds through and the
more you have to deal with it.

~~~
dymk
Certainly not; see for instance asm.js. Arbitrary C++ (or any other LLVM
language) can be translated into JS this way.

~~~
ori_b
Except wasm isn't JS. It's yet another vm in the browser.

~~~
dymk
You're right; I mean asm.js. Point stands. You can compile arbitrary languages
into JS without the "js" part leaking through.

~~~
gridlockd
The JS part definitely leaks through even with asm.js, particularly the lack
of native 64-bit integers.

The further away you go from Javascript, the more performance issues you
encounter and the larger your build size becomes.

Of course in theory nothing stops you from having an entire turing-complete VM
inside JS, but that's not what you want for real deployments.

------
lovasoa
I think the comparison in the redux example really isn't fair. He defines just
one enumeration in ReasonML and uses many different constants and interfaces
in Typescript.

The equivalent of

    
    
        type action =
          | AddMovie(string)
          | RemoveMovie(string)
          | Reset
    

in Typescript is more something like :

    
    
        type Action =
          | { type: "ADD_MOVIE", movie: string }
          | { type: "REMOVE_MOVIE", movie: string }
          | { type: "RESET"};

~~~
nirvdrum
Since TS is just JS, you could just dispatch to arbitrary strings, but the TS
type system isn't going to help you out very much. The approach the author is
taking is the one described in the Redux documentation [0].

[0] -- [https://redux.js.org/recipes/usage-with-
typescript](https://redux.js.org/recipes/usage-with-typescript)

~~~
acemarke
Hi, I'm a Redux maintainer. FWIW, there's apparently a ton of ways to handle
typing Redux with TS (and that's even reflected in the discussion for the PR
that added that page [0]). A large part of it seems to revolve around whether
or not you're trying to apply action types to `dispatch` to limit what actions
can be dispatched.

I'm comfortable with TS at a general level (declaring interfaces for API
types, reducers, and React component props), but a lot of folks seem to go
crazy trying to get 100% type coverage. I personally aim for more of an "80%"
sweet spot for typing - trying to trade off overall benefit with not trying to
tie myself in knots adding ridiculous type declarations.

I actually just wrote a tutorial page for Redux Starter Kit that shows how to
use it with TS and `useDispatch` [1], but had someone point out that one of
the examples I was using for thunks was losing a bit of type safety [2]. This
stuff is hard :)

[0]
[https://github.com/reduxjs/redux/pull/3201](https://github.com/reduxjs/redux/pull/3201)

[1] [https://redux-starter-kit.js.org/tutorials/advanced-
tutorial](https://redux-starter-kit.js.org/tutorials/advanced-tutorial)

[2] [https://github.com/markerikson/rsk-github-issues-
example/pul...](https://github.com/markerikson/rsk-github-issues-
example/pull/1)

~~~
nirvdrum
Thanks for the feedback. The earliest examples I had see of using redux just
passed strings around and struck me as being error-prone. So I was happy to
see const fields used as the action types. The TypeScript approach looks
reasonable to me, if not verbose. But it looks like there's no real consensus
on what the best practice is. Certainly some food for thought. Thanks!

------
jameskraus
I wish this comparison included more information about the developer
experience of TS vs Reason. In my off time I've tried out Reason, but one of
the major sticking points was how _poor_ the experience was setting up an
editor with autocomplete and type hints. You get that basically out of the box
with TS, but Reason & OCaml have a more fragmented ecosystem, so it's much
harder to get started and feel productive.

IMO, the beautiful type system is nice, but the DX with TS is much more
productive than Reason or OCaml.

PS: Do you think my comment is dumb? Reason/OCaml are easy to set up? It's as
easy as 1-2-3? Please link me tutorials or resources that prove me wrong. I'd
love to get started, but DX has been the major hangup again and again.

~~~
Dude2029
Every technology created at Facebook is meant for internal use. The wider
community then goes through the pain of making it usable. Microsoft's mission
on the other hand is pleasing developers hence VS Code and TS.

~~~
tyri_kai_psomi
Rust was created to solve's Mozilla's problems with C++

Go was created to solve Google's problems with C++ and engineering at scale

The fact that TypeScript wasn't created to solve a big issue internally at
Microsoft _is exactly_ what makes me skeptical of it and personally I view it
as a trojan horse, just like VSCode. Sure, today it is done for benevolent
reasons, maybe, but what about tomorrow? What if that trillion dollar market
cap starts tanking? Then The benevolent VSCode and TypeScript ecosystems
become levers to pull in the great big machine.

I would almost feel better if I knew it's stated explicit purpose upfront and
what Microsoft's long term goals to monetize the ecosystem/platform were,
because then I know what I am signing up for.

~~~
WorldMaker
Typescript _was_ created to solve big issues internally at Microsoft, to deal
with JS at scale. Microsoft has _huge_ JS codebases, almost all of which are
Typescript today. Office.com (including in-browser, online versions of Word,
Excel, PowerPoint), Outlook.com, OneDrive.com, portal.azure.com,
dev.azure.com, and so on. Microsoft may not be as recognizably a "web
applications" company, but they do have a number of really big web
applications, and they had real scaling problems with JS that Typescript was
directly built to help with.

VSCode was started to see if they could build a good web application for
development. Portions of it directly power a number of tools of Azure (on
portal.azure.com), portions of it also directly powered the Dev Tools inside
IE10+ and Edge "Classic". Bundling the web app into an Electron container
after it had already paid for its own engineering efforts several times over
as reusable sets of components for multiple large web apps Microsoft needed
hardly seems like a "trojan horse" to me.

------
pbowyer
I didn't think much of this article ("Another biased comparison, yawn") until
I got to the Reducer example.

I read up on reducers for Redux and Cycle.js, but avoided using them. The
Typescript examples are so cumbersome; I'd rather do something else where my
code is more understandable.

But in ReasonML it's elegant. It's awesome! I'd choose to use that.

Sure they do the same thing. But as the developer who has to commit to reading
and maintaining this code, I know which I'd rather write and come back to in
18 months' time.

~~~
undecidabot
Looks like another biased comparison to me. You could easily rewrite the
TypeScript reducer example (which fails to compile btw) to be similarly
concise while being as safe.

    
    
      interface State {
        movies: string[]
      }
    
      // you may also use { tag: "Action", payload: string }
      // if you prefer something more structured
      type Action =
        | ["AddMovie", string]
        | ["RemoveMovie", string]
        | ["Reset"]
    
      const defaultState: State = { movies: [] }
    
      const reducer = (state: State, action: Action): State => {
        switch (action[0]) {
          case "AddMovie": return { movies: [action[1], ...state.movies] }
          case "RemoveMovie": return { movies: state.movies.filter(m => m !== action[1]) }
          case "Reset": return defaultState
        }
      }
    
      const someAction: Action = ["AddMovie", "The End of Evangelion"]
    

TypesScript's type system is actually very flexible and advanced [1] compared
to most type systems since it had to adapt to the very "dynamic" structuring
of JavaScript in the wild.

[1] [https://www.typescriptlang.org/docs/handbook/advanced-
types....](https://www.typescriptlang.org/docs/handbook/advanced-types.html)

~~~
hajile
ReasonML variants are type constructors. Your example completely eliminated
all action creators (constructors). Once you add those functions back, most of
the type bloat reappears.

I wouldn't want to work on a project where everyone was creating object
literals and passing them to dispatch everywhere.

~~~
undecidabot
Yes, I eliminated the action creators. I don't see why they're necessary
(maybe there's something about redux I'm missing?). The type constructors of
ReasonML cannot be used as functions, so I think my rewrite is fair.

If you insist on having the action creators, they can easily be written as one
liners each, which is a lot less bloated than the original example.

    
    
      export const addMovie = (movie: string): Action => ({ tag: "AddMovie", movie });
    

What's the issue with passing object literals? I know it looks a bit hacky and
messy, but if it's typesafe (which it is) then it doesn't seem like a real
issue.

~~~
hajile
No action creator is a serious refactor concern.

Let's say you need to update your function signature with an additional,
optional parameter with a default value. You can go to the definition of the
action creator and change it. Since you've defined an interface for the action
object, finding reducers that use it will be reliable and easy.

If such a creator doesn't exist, you must grep your codebase for every
instance of the object and ensure they deal with the optional bit. Murphy's
Law guarantees that someone will have decided to procedurally generate the
object making finding every instance very hard. Next, you have that reducer
lookup, but you don't have a shared interface, so you're stuck in grep land
once again to find all the reducers.

Finally, copy-pasting an object literal all over generally results in a larger
bundle than reusing an action creator which is smaller and also minifies
better.

~~~
undecidabot
If the lack of action creators is a serious concern, then the one-liner-each
action creator I suggested should be sufficient without adding much bloat. How
would the ReasonML example deal with that change though? Can the variant
constructors take in optional parameters?

Using Murphy's Law is not very convincing. Even with action creators Murphy's
Law guarantees someone would have just constructed the objects manually
anyways. Having to grep the tag is not ideal, but it's not likely to be a
problem in practice.

I doubt that the bundle would be significantly larger (especially after
compression). Using actions creators introduces additional (function call)
overhead too (and that would be insignificant as well).

------
eatonphil
The most pragmatic reason to use TypeScript is for gradual typing of existing
codebases, and that all JavaScript is valid TypeScript. You can introduce
TypeScript over time and if it doesn't work out for your group, you can delete
the TypeScript-specific annotations and go back to Babel. Or you can keep
TypeScript to only specific parts of your application/library.

The most pragmatic reason not to use TypeScript is because it is static-only.
And that is easy to forget. That is, within any arbitrary function X you have
no guarantee the parameters passed to X are the type specified in TypeScript.
There isn't a ton you can do about this except for to code very defensively
where it matters.

I've used TypeScript for a number of projects professionally, introducing it
among developers familiar and unfamiliar with static typing. I'm not really
interested in going back or finding alternatives for now. It is a huge help in
development and refactoring without a huge cost.

~~~
siempreb
> and if it doesn't work out for your group, you can delete the TypeScript-
> specific annotations and go back to Babel.

You are joking right? Ever tried to do that with a large Typescript code base
and then of course without the defensive strategy? It's a myth Typescript
proponents really enjoy to believe.

> There isn't a ton you can do about this except for to code very defensively
> where it matters.

Bingo! That's what I always did and served me well on very large code bases.
With Typescript I have to write about 20% more code(that can hide bugs too).
Advantage? A bit more intellisense than VScode gives already out of the box,
and of course for the junior and medior developers so they cannot mess
up(types).

~~~
wwwigham
It's probably worth noting that that the "intellisense that vscode gives out
of the box" is _also_ still delivered by TypeScript. Slap a `//@ts-check` into
a js file and you'll find just where the typechecker thinks your jsdoc or
usages are lacking or confusing (then maybe add a jsconfig with stricter
settings than the default!). If you then fix those, you should be capable of
getting _nearly identical_ completions in js and ts (because they really are
just variants of the same language).

IMO, TS is all about static enforcement of inline documentation (types), just
like how a linter enforces style. You can choose not to enforce it
automatically... But at this point I don't get why you wouldn't? I wouldn't
argue that style enforcement is best done by hand in the code review stage...
So I don't see how further quality checks based on semantics derived from
documentation would be any different.

------
tomp
_> Why don’t we have to write types in ReasonML? Because of the powerful type
system that allows for incredible type inference._

You mean the _restricted_ type system that allows for _principal_ type
inference? ML's type system is much less powerful than Haskell's or Scala's,
precisely _to allow_ type inference (e.g. no overloads). The type inference
itself isn't very powerful or incredible either, it works _just_ for the exact
type system offered by ML.

Obviously nobody likes this, which is why ML offers a number of hacks to allow
more powerful type system hackery - e.g. open sums ("polymorphic variants" and
also open exception types), HKTs (modules), GADTs, row types & subtyping
(objects). Although IMO it would be better to incorporate all these hacks in
the core language itself, and only run type inference on the bits where it's
possible (but of course tradeoffs would be necessary to avoid running into
halting problems etc.).

~~~
sweeneyrod
Yes, that sentence should've probably been "Why don't we have to write types
in ReasonML? Because of the powerful type inference system". But I think
comparing to Haskell is kind of missing the point: you can't use that for
front-end web development. Also, I'm not sure what you mean by saying those
"hacks" aren't part of the core language.

~~~
tomp
By “hacks” I mainly meant that they don’t play that nice with type
inference... type annotations are sometimes needed. Also that they were added
to the language later, in order to make the type system more powerful.

------
philplckthun
It's great to see more comparisons and articles about ReasonML and this one is
really concise! But I do wish articles were more clear about the relationship
between ReasonML, OCaml, and Bucklescript.

> It is also interesting to look at what javascript was generated by ReasonML

This is where BuckleScript should probably be mentioned first. TypeScript is
both the name for the language and the tsc compiler, since it's a single
project. But with BuckleScript that's not the case.

> BuckleScript is _the tool_ that transpiles ReasonML to JavaScript.

There's also the older js_of_ocaml (JSoO) project, and there's more great
Reason/OCaml tooling for native, like esy and dune! It's really exciting, but
these small details are rather interesting and it's important to highlight
them to avoid confusing beginners.

~~~
k__
As far as I understood is esy uses dune and dune uses BuckleScript, so they
aren't alternatives.

~~~
brmgb
Sadly, BuckleScript tries to do everything. It ships with a not so-great build
system, a good compiler to javascript, a standard library replacement and it
invites you to use npm for package management.

Dune is the build system which has become the standard in the Ocaml community.
It can use the native compiler or js-of-ocaml to produce javascript. It
doesn't support BuckleScript however.

Esy is a tool which allows you to manage your project dependencies. It can
pick package from both opam and npm and uses Dune as a build system. It's
actually very good.

As Facebook mostly pushes ReasonML towards Javascript developers, they mostly
advertise BuckleScript. From what I have seen, the Ocaml community mostly does
not care about Reason. They had no issue in modifying tools to support it and
noone is going out of its way to hinder it but there is no particuliar
enthusiasm towards it.

~~~
yawaramin
> there is no particuliar enthusiasm towards it.

There's no particular enthusiasm towards quite a lot of things in the OCaml
community :-) there are even some holdouts who don't like or use dune/opam. I
wouldn't take that as a point against ReasonML/BuckleScript, which is bringing
devs en masse to OCaml who would have never looked at it before.

------
blunte
Yes please! I would absolutely rather use ReasonML than TypeScript or
JavaScript; so I hope it gains a lot of traction.

I'd still rather use ClojureScript, though.

~~~
jecxjo
Can I ask why?

I came from low level language background but my "fun programming" went from
Lisps to MLs and now I have difficulties going back to Lisps for projects.
Always wanted to like Clojure but never had a need for JVM in anything I
worked on.

~~~
blunte
My little brain can't keep up with too many things (in short term memory) at
once, so more concise and expressive languages are better for me. Also, more
sane languages are better (where it's harder to shoot yourself in the foot
because you're not (yet) very good at the language).

The homoiconicity of Lisps allow me to think less about syntax. (function
<args...>). And reading code is easier, since I see the operations first.
Adding more advanced features (via macros) can give you lovely function
chaining - threading, piping, etc.

Immutability in Clojure is also good for me because it allows me to learn and
forget about functions. Black boxes are great things when you can trust that
they are pure functions; just compose bigger black boxes and so on.

I don't do a lot of Clojure these days, but when I was using it professionally
I could basically forget about JVM; JDBC was about the only time I interop-ed
with Java. If you need some of the good things that JVM offers, great; if not,
it's just a hosting environment. Same with Elixir and BEAM (although JVM and
BEAM are very different and tailored for different problem sets).

But on topic, given a choice between ReasonML and JavaScript, it seems to me
that ReasonML is more thought out, cleaner, safer, and a step in the right
direction.

~~~
hota_mazi
My little brain can't keep up with too many things either, which is why I only
use statically typed languages.

Dynamically typed languages force me to keep type information in my head, and
that's just not a good use of my brain when the compiler can be so much better
than me at this.

~~~
TurboHaskal
I don't want to take a side in the dynamic vs static typing debate, specially
since my favourite languages are Common Lisp and OCaml and it would be
difficult for me to choose either, but I wouldn't say your argument of having
to keep everything on the head holds if we consider the whole array of dynamic
language offerings.

Compared to toys like Perl, Ruby, Python, etc., proper dynamic languages
(Lisp, Smalltalk) have state of the art debuggers, browsing and
discoverability tools and let you backtrack, experiment and tweak your program
in an iterative fashion. They are indeed "little brain" friendly and the
development experience matches or surpasses those of compilers and classical
IDEs.

I am so much more productive in LispWorks than, say, IntelliJ+Java it isn't
even funny.

------
truth_seeker
Yet another day, yet another incomplete and immature language comparison blog
!

I really wish to see some mature blog post which in depth covers the merits of
languages in comparison by writing a large enough and workable piece of code
solving the identical problem and utilizing all features of individual
languages in their specific codebase.

If the author would have been really unbiased about TypeScript he must have
mentioned at least 2 (but not exhaustive) following things.

1\. Advance TypeScript Types

[https://www.typescriptlang.org/docs/handbook/advanced-
types....](https://www.typescriptlang.org/docs/handbook/advanced-types.html)

2\. Number of existing JS libraries TypeScript already supports

[https://github.com/DefinitelyTyped/DefinitelyTyped/tree/mast...](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types)

Most people are just stuck with ES5 and callbacks. I have conducted many
(about 12 so far) meetups here in India on new features of ES6/ES7/ES8 and
using them to build small full-stack JS/TS assignment with TDD for various
kind of senior devs coming from Go, Java, Scala, Python and Ruby.

Common reaction from them I receive very often "We never knew that JS/TS can
do that"

~~~
nirvdrum
The author mentions DefinitelyTyped:

"DefinitelyTyped typings amount is just insane and it will take time for
ReasonML to match them."

I agree it would be nice to have an expert analysis of a reasonably-sized
application, but that is a rather large undertaking. And frankly many devs
aren't experts in two "competing" ecosystems. If you spend the bulk of your
time in ReasonML, you're apt to fall behind on TypeScript's recent
developments. What you see as bias may just be simple ignorance.

I've just started playing around with ReasonML in the past week, and
everything the author has hit upon has been relevant. Writing reducers in
ReasonML is a treat. But, the language server isn't nearly as good and there
aren't many annotated libraries, so I have to fall back to BuckleScript's JS
interop support. The interop system is well-done, but it's extra overhead I
wouldn't have to deal with otherwise.

~~~
loxs
"it will take time for ReasonML to match them"

Nope, it will never match them if they both keep their current speed. The
contrary - the rift will become bigger and bigger.

~~~
nirvdrum
I didn't make the claim nor am I supporting it. But the author definitely
mentioned DefinitelyTyped as a positive for TypeScript.

~~~
loxs
I know. It was not a comment to your words, but to OPs, just to give more info
to people not familiar.

~~~
nirvdrum
Gotcha. My misunderstanding.

------
waltera
I got interested in Reason last year after reading lorefnon's article [1]
comparing Reason with TypeScript.

Recently, after evaluating both for a large project we decided to prefer
TypeScript primarily because TypeScript's support for intersection types,
mapped types and conditional types is really awesome and make integration with
javascript libraries a lot easier. As far as I could find, similar things
can't be done in ReasonML at all (although I could be wrong on it).

The tooling integration of TypeScript is also really awesome. Besides the
usual refactoring, jump to definition support etc. a lot of effort has gone
into small things that makes life easier. For example, if you have ctrl+click
on a mapped type's property it will jump to the original type being mapped. In
libraries like io-ts if you add doc comments on methods which are used to
derive the types, the documentation will be propagated to the derived types
[2].

I recently found that the author of the above post has been experimenting [3]
with babel-macros [4] to facilitate nice type-safe fluent APIs/abstractions
which are compiled away to simple readable javascript with zero/negligible
runtime overhead and found it a really neat idea. Looking at some of that
code, it appears to be a lot simpler than writing ppx macros [5] for ocaml
which I very briefly experimented with.

[1] [https://lorefnon.tech/2018/05/13/reasonml-vs-typescript-
firs...](https://lorefnon.tech/2018/05/13/reasonml-vs-typescript-first-
impressions/)

[2] [https://github.com/gcanti/io-
ts/issues/201#issuecomment-4347...](https://github.com/gcanti/io-
ts/issues/201#issuecomment-434721076)

[3] [https://github.com/ts-delight](https://github.com/ts-delight)

[4] [https://github.com/kentcdodds/babel-plugin-
macros](https://github.com/kentcdodds/babel-plugin-macros)

[5] [http://ocamllabs.io/doc/ppx.html](http://ocamllabs.io/doc/ppx.html)

------
thekillerdev

      Why don’t we have to write types in ReasonML? Because of the powerful type system that allows for incredible type inference.
    

wat? [https://www.typescriptlang.org/docs/handbook/type-
inference....](https://www.typescriptlang.org/docs/handbook/type-
inference.html)

~~~
a0
Many modern languages support type inference to some degree. The special thing
about ReasonML is that the type inference is much more robust and complete.

In practice you don't need to provide any types annotations at all at any
point in your program and you should still get the same safety benefits.

Every value in your code will automatically have one single type assigned to
it based on how it is being used. When the compiler finds contradictions it
will let you know about it. On the other hand, Typescript will try to unify
the type to some sort of Any, which is probably not what you want.

~~~
gridlockd
Why do people care about this? Writing type annotations is not that much work,
but they make your code more readable.

I can see the argument for it when you have unspellable nested generic types,
or when you don't want to write the same thing on both sides of an assignment.
Simple type inference like in TS gives you that.

Having really smart type inference makes your compiler slower and more
complicated. What's the real-world benefit?

> Typescript will try to unify the type to some sort of Any, which is probably
> not what you want.

Not really, unless you push the type inference beyond its limits, in which
case you should just change your code.

~~~
a0
Many interesting points! :)

> Why do people care about this? Writing type annotations is not that much
> work (...)

I personally care about this when I'm prototyping something. Not having to
write types means that I can simply write what's on my mind. The benefit of
good type inference is that the compiler can still help me highlight any
mistakes I made during this process.

Another benefit is that some production code can get very complex. Having to
type every single value is just too cumbersome and distracting. It contributes
to boilerplate and increases cognitive load, in my opinion.

> Having really smart type inference makes your compiler slower and more
> complicated.

I would actually disagree with this. First of all, ReasonML's compiler is
absurdly fast. No, seriously try it. Sometimes I go and double check the
generated JS code just to be sure it actually did anything.

Regarding the "more complicated" part – the only reason why full type
inference works is because it is based on a very solid theoretical foundation.
It might be somewhat "complicated", but it will never be as complicated as
something ad-hoc that needs to account for all inconsistencies that exist in
untyped languages like JavaScript.

~~~
johnisgood
> It contributes to boilerplate and increases cognitive load, in my opinion.

In my experience with OCaml, I found that knowing the types of my variables
reduce the cognitive load of trying to infer the types myself when reading the
code, so despite OCaml supporting type inference, I use explicit type
annotations almost everywhere.

~~~
a0
Being a Vim/Merlin user I normally just type `<Leader>t` to see the type of
the value under the cursor (this maps to `:MerlinTypeOf` if I recall
correctly).

What I do use type annotations for is debugging. If the compiler finds a type
error, in some situations it helps adding type annotations to find where the
actual error is.

~~~
johnisgood
I do use that feature, too, for functions, in Emacs. So in the mode line I see
for example: _Array.length: 'a array -> int_. I find it quite useful.

------
dmitriid
The problems I ran into with ReasonML (last year) is how scarce the ecosystem
is and how incomplete the bindings.

I remember trying to fetch stuff. Fetch wrapper returns data in a type that is
not convertible to anything. Ex. it returns Fetch.Uint8ArrayBuffer instead of
Uint8ArrayBuffer. Because reasons.

And the compiler was entirely unhelpful. “X provided but somewhere required Y”
is the best you could get for type errors. Somwhere... _where_?

ReasonML is very very early on adoption curve.

------
jbverschoor
It's simply incorrect..

> Although I didn’t write any types by hand, the arguments of this function
> are typed. Why don’t we have to write types in ReasonML?
    
    
      let sum = (a,b) => a + b;
    

Is perfectly fine for typescript too. As for:

    
    
      let formatName = product => "Name: "+product.name;
    

So I stopped reading there.

~~~
koolba
Does ReasonML infer that a type "Product" is the only one in the visible
namespace with a "name" property or does it infer at use time that the
formatName(...) invocation is valid because the argument has a "name"
property?

They're separate concepts. Maybe I want to ensure that I'm receiving a product
as it makes no sense to invoke formatName(...) on other things with names like
a Cat or Person.

And the generic "thing with a name" one is possible in TypeScript too:

    
    
        const formatName = (product: {name: string}) => "Name: " + product.name

~~~
masklinn
> Does ReasonML infer that a type "Product" is the only one in the visible
> namespace with a "name" property

Yes.

> does it infer at use time that the formatName(...) invocation is valid
> because the argument has a "name" property?

No. OCaml does have a structural object system
([https://v1.realworldocaml.org/v1/en/html/objects.html](https://v1.realworldocaml.org/v1/en/html/objects.html))
and it is available to reason, but it's syntactically funky
([https://reasonml.github.io/docs/en/object](https://reasonml.github.io/docs/en/object))
and as far as I can tell TFA does not use it.

> They're separate concepts.

Yes. Which is why OCaml (and thus Reason) separates it[0] from the nominative
"structures".

> Maybe I want to ensure that I'm receiving a product as it makes no sense to
> invoke formatName(...) on other things with names like a Cat or Person.

You're really deep into this strawmanning thing.

[0] pretty completely, you can't use nominative types in a structural context,
they are _not compatible_. In fact structural types are sets of methods,
something which doesn't exist on the nominative side.

~~~
koolba
I didn’t mean it as a straw man. I’m not familiar with ReasonML at all and
meant to illustrate the example.

------
Illniyar
>It is also interesting to look at what javascript was generated by ReasonML
``` function updateName(product, name) { return [name, product[1]] } ```
Records in ReasonML are represented as arrays. And generated code looks like a
human wrote it if humans could remember indices of every property of every
type like a compiler does.

This seems like a massive headache, what about JSON? or accessing
dictionaries? Do you need to parse every js datastructure to a ReasonML
record?

~~~
pkilgore
No. Reason (bucklescript really) maps to the full range of a data structures.
So use a dict as a dict, a record as a record, an array as an array...etc. It
will map back to what makes the most sense in the JS world.

As opposed to JS, where really all these things are overloaded onto the same
data structure ( object ).

------
loxs
After one year of OCaml/ReasonML and after that one year of TypeScript, I will
not go back to Reason.

1\. TypeScript has a better (more practical) type system (for the task of
writing a WEB UI and interop with JS).

2\. TypeScript is actually usable by people who do not have a PhD in type
theory.

3\. TypeScript has tools. This is a huge difference.

4\. It's faster and cheaper to actually develop a product in TS than in
Reason/OCaml.

5\. Yeah, TS lets through more bugs, but it's actually just a small blip on
the radar.

In practice, TS makes it quite possible to get all of the benefits that OCaml
claims without actually paying any real price.

edit: formatting

edit2: I still do use and love OCaml (on the backend), just not fooling myself
I can actually ship a real (and big) web UI project using it.

------
kangar00857
I understand it’s a major sin to ever talk about syntax but a lot of ReasonML
reads like someone’s cat walked across the keyboard

This project is interesting & the folks evidently involved & advocating
invested a lot time + smarts but why bother with all this new cognitive load &
new universe of subtle problems (bucklescript, interopt, external libs, etc)?

~~~
kangar00857
(Not trolling, no flamewar but asking out of curiosity)

Is ES6 + Typescript in 2019 really so awful that all this effort is required
to build rich applications for web?

Perhaps ReasonML is like “the big guns”, but what situation makes it
necessary/important/better to use?

~~~
jasim
This might shed some light:
[https://www.harigopal.in/talks/2018/jsfoo](https://www.harigopal.in/talks/2018/jsfoo)

------
cjdell
I tried really hard to use ReasonML about a year ago but ran into a road block
with the lack of async/wait (or equivalent) syntax. It's really cumbersome to
have to go back to chaining callbacks again.

~~~
bgorman
You don't have to chain callbacks, you can use monadic Future libraries. Look
into "Future" for bucklescript, or "Lwt" for reason-native.

------
redleggedfrog
I think where these comparisons go wrong is tooling. I don't give a rodent's
behind how nifty your new language is unless you've got excellent tooling,
particularly, an easy to use step through debugger (and no, you still need a
debugger when functional programming).

The second I think I'm doing printf() debugging I'm out.

Note, I'm only referring to actually getting work done here - academically, or
if you're just dinking around, then it's all good.

~~~
loxs
This, and also proper out-of-the-box IDE for refactoring, completion etc.
Reason/OCaml do have the proper IDE, just not out-of-the-box.

------
gridlockd
None of these are worth switching to a fringe ecosystem for.

The compile-example is misleading. Clean build times don't really matter.
Iteration times with "tsc -w" would've likely been well under a second.

The boiler-plate in the redux example could be reduced, but redux itself is
extremely boilerplate-heavy when written in this explicit style. It would be
interesting to see how the ReasonML typesystem gets in the way of
metaprogramming.

~~~
sikan
At work our TS project with a thousand files takes 30mins on CI, incremental
save takes at least 20 second. Half of the time makes the machine run out of
memory.

Bucklescript can have a clean build of 1.2k files project in under 4 seconds!
[https://twitter.com/bobzhang1988/status/1160846763747508224](https://twitter.com/bobzhang1988/status/1160846763747508224)

~~~
gridlockd
Thanks for the data point. Those aren't the same thousand files though.

If your project has a thousand source files of _any_ programming language,
it's probably time to quit and join a younger company.

------
rictic
I love languages, and I want to use languages with powerful, sound type
systems on the web, but I don't want to do it at the cost of shipping much
larger amounts of code, making for a slow initial render.

A vanilla JS todomvc app is 10KB of JS (plus some analytics code for some
reason): [http://todomvc.com/examples/vanilla-
es6/](http://todomvc.com/examples/vanilla-es6/)

The production build of the ReasonML todomvc app ships 5x as much, 56KB JS.

How much of that is a static runtime cost, and how much is just the cost of
translating ReasonML into the corresponding JS? An extra 40KB isn't great, but
it's not a dealbreaker. A shipping 4x-5x as much JS would be, in a lot of
cases.

~~~
chenglou
Eh where did you see that? ReasonReact is runtime-free, unless you’re
explicitly using some of the extra helpers.

~~~
rictic
I ran the production build of [https://github.com/reasonml-community/reason-
react-example/t...](https://github.com/reasonml-community/reason-react-
example/tree/master/src/todomvc) and ran the JS bundle through gzip -9 to get
the 56KB number.

~~~
chenglou
Oh man, that repo's stale. The official instructions are here:
[https://reasonml.github.io/reason-
react/docs/en/installation](https://reasonml.github.io/reason-
react/docs/en/installation)

------
devmunchies
doesn't say this in the post, but ReasonML was created by the same developer
that created React. Which would indicate it is good for generating UIs in the
browser but not necessarily all the other stuff JS does (interacting with
browser APIs and stuff)

I'm a big fan of OCaml, so I would like to see more developers dogpile on a
functional UI language like ReasonML so it improves.

------
bkonz
While I can't speak specifically to ReasonML, I have used Ocaml and Typescript
extensively in [https://www.jeroo.org/beta](https://www.jeroo.org/beta).

I used Ocaml to write the a (simple) custom compiler framework, which gave me
the benefits of better type safety than Typescript.

Typescript was used with Angular to create everything else (the custom-
bytecode interpreter and user-interface. Typescript gives me the advantage of
good interop with Javascript libraries, mainly CodeMirror for the editor.

The interop with Ocaml and Typescript was pretty good. I just exported the
Ocaml as a Javascript module using Js-of-ocaml with one exported function that
starts off the compilation. Then it returns a list of a custom instruction
object, which acts as a 5-tuple with all of the instruction fields.

------
city41
The article mentions a non handled case in a switch is flagged in Reason but
not TypeScript. That is technically true, but you can flag an unhandled case
by adding a default case which takes advantage of the never type

[https://stackoverflow.com/questions/39419170/how-do-i-
check-...](https://stackoverflow.com/questions/39419170/how-do-i-check-that-a-
switch-block-is-exhaustive-in-typescript)

~~~
loxs
This isn't needed any more. Modern TS enforces switch exhaustiveness out-of-
the box (if you provide the proper union type, of course).

~~~
sikan
This is not true: [https://www.typescriptlang.org/docs/handbook/advanced-
types....](https://www.typescriptlang.org/docs/handbook/advanced-
types.html#exhaustiveness-checking)

~~~
loxs
Yeah, I always use strict and specify return type. IMO, still counts.

------
lucaspottersky
> "And while having that familiarity with JavaScript is nice, it means that
> every quirkiness that we love and hate about JavaScript is still there in
> TypeScript

> "... ReasonML is everything TypeScript tries to be (and a bit more) without
> all that JavaScript weirdness."

yeah, but what makes the author think that __INSERT NEW LANGUAGE HERE__ would
not have other 'quirkiness'?

------
philliphaydon
I’m not a fan of TypeScript, and never heard of Reason, but this post makes me
like TypeScript more. I prefer the fact it’s more explicit and less magic.

The examples in TS are very easy to understand where Reason just looks like
magic and I have to think more about what it might be doing. I don’t see a
benefit to Reason over vanilla JS.

/opinion

~~~
Rapzid
F# tackles this disconnect between working on the code in an IDE and reading
code with an interesting documentation system:
[https://fsprojects.github.io/FSharp.Formatting/metadata.html](https://fsprojects.github.io/FSharp.Formatting/metadata.html)
. Mouse over the code :)

~~~
devmunchies
i hate those tooltips when they get in my way. I wish they only showed up if
you hold control + hover or something like that.

------
Can_Not
Would love to use typescript or ReasonML with something other than react, like
svelte.

------
muglug
I get the sense that ReasonML exists because some smart people see "JavaScript
developer" as a pejorative.

While its abstractions make plenty of sense, its distance from JavaScript
makes it incredibly unappealing to the average developer.

~~~
a0
This kind of comments make me really sad. Most ReasonML developers are
actually "JavaScript developers".

ReasonML was specifically designed for JavaScript developers. Being
JavaScript-friendly is in it's DNA really. I even see ReasonML a language that
was specifically designed to work with React.

I can understand why you would feel this way though. I think the main problem
is that ReasonML introduces new concepts that simply do not exist in
JavaScript. Learning those concepts is hard. But if it wasn't hard, would you
be learning anything or just writing JavaScript in a slightly different way?

Are there any specific examples of things that look too "distant" from
JavaScript?

I'll finish this by saying that ReasonML will make you a better JavaScript
developer. As will probably learning any other language that challenges the
way you think.

~~~
muglug
> I'll finish this by saying that ReasonML will make you a better JavaScript
> developer. As will probably learning any other language that challenges the
> way you think.

I wholeheartedly agree! But a lot of people don't want to be challenged by the
language when there are already plenty of other challenges in their personal
and professional lives.

With TypeScript you don't need to think half as much, and the thing your boss
generally cares about (whether the feature shipped) gets done.

~~~
yawaramin
> With TypeScript you don't need to think half as much

That seems a bit dangerous, to be honest. TypeScript has an unsound type
system. If you don't think carefully, you might end up shipping runtime type
errors.

------
lucasmullens
For the "Null, undefined vs Option" part, it's feasible with a lint rule to
ban null throughout your code. Might not work for third-party code, but Reason
can't work with that anyway.

------
stephen
I inherited several Flow codebases, which is from the same guy/group as Reason
at FB, and attempted to do the same goal of "bah explicit type annotations,
let's infer everything".

This nearly ruined the codebases and we ended up converting them all to TS
because:

A) tactically, flow's global inference sucked, so many things that devs
thought were typed, were not. I get they're trying a do-over and using OCaml
to solve that this time around, which I agree is fundamentally a better
approach.

B) strategically, explicit type annotations (i.e. at method boundaries) is a
_feature_ for dev readability and comprehension and not a burden to be
avoided. I get that Flow/Reason _can_ add these type defs, but many new devs
see posts like this, think "nice, less chars to type!", and now write a 100k
LOC codebase with a pervasive lack of any type defs.

Tldr, I think TS's explicit types at boundaries is actually best practice for
programming-in-the-large.

~~~
toolslive
> explicit type annotations (i.e. at method boundaries) is a _feature_ for dev
> readability and comprehension and not a burden to be avoided

The problem is not the type inference, but tooling. If your IDE can, when
you're coding can 'show-type-at-point' and your online github style code
review tool shows the type of any expression, argument, ... when you hover
over it, you no longer have this problem.

------
k__
Anyone knows good ReasonReact tutorials where people build a full app?

~~~
yawaramin
Yes–check out this excellent blog series
[https://dev.to/seif_ghezala/reasonml-for-production-react-
ap...](https://dev.to/seif_ghezala/reasonml-for-production-react-apps-
part-1-3nfk)

------
cztomsik
javascript/typescript is great if you don't know what you're going to
eventually come up with but you need to iterate fast and keep it high-level
with lots of TODOs and uncertainties which would otherwise have been hard to
type.

if there's anything I really, really hate it's when I'm just trying something
and keep getting compiler errors for things I'm not even interested ATM.

------
indeyets
I wonder how ReasonML is positioned against Flow. Both seem to fill the same
niche at facebook (and both lack marketing resources of TypeScript).

------
duckqlz
Great comparison I was interested in reasonML and find comparisons like these
very helpful. Still sticking to ELM for my personal projects!

~~~
crimsonalucard
ELM really needs type variables and type classes.

~~~
hashbig
Anything declared in Elm is immutable so types on constants become way less
relevant.

~~~
crimsonalucard
Type variables are not what you're thinking.

    
    
       add :: Int -> Int -> Int
       add a b = a + b
    
       add2 :: a -> a -> a
       add2 c d = c + d
    

1st function adds integers. 2nd function adds anything that can be added. For
example: add2 [1,2,3] [4,5,6] evaluates to [1,2,3,4,5,6]

The 'a' in the second function is a type variable.

------
rambossa
How is dev ex with Reason? Intellisense?

~~~
a0
It's ok. There's pretty good support for linting and code completion. The
plugins are fast and have a rich feature set.

Take a look at this:
[https://marketplace.visualstudio.com/items?itemName=jaredly....](https://marketplace.visualstudio.com/items?itemName=jaredly.reason-
vscode)

The only problem that I have found is that in some situations it doesn't
report errors correctly when adding new dependencies. Refreshing the window or
rebuilding the project usually helps.

On the other hand, the compiler feels very solid. It can be annoying in the
beginning because of how disciplined the code needs to be, and the error
messages can be hard to understand.

After getting used to that, the dev ex is really smooth specially during
complicated refactoring, the compiler and the IDE make things almost boring.

------
rammy1234
when comparing the language construct, usually adoption is hindered by
tooling. You should also compare tooling. that said, this is an excellent
article trying to reason out why we should start using ReasonML

------
crimsonalucard
In mathematical theory, the variant type is actually the theoretical opposite
of a "struct" type. Mathematicians know this through the functions that apply
to each type.

Simply inverting the direction of functions that describe a "struct" type
creates a structure that exactly describes a variant type.

The theory points to opposites but language writers, unaware of theory, more
often than not leave out the critical primitive that should be intrinsic to
all programming languages.

