Thomas Bandt

Type-Safe Single Page Apps: F# Vs. TypeScript

While there are many UI libraries available today to build modern web apps, the number of programming languages that compile to JavaScript has also increased in recent years. Here is a quick take on F# and TypeScript.

Published on Friday, 03 July 2020

Preface

Although I did focus on mobile apps in the last years, I've spent the first decade or so of my career concatenating strings, also known as web development. So I think I might know a thing or two about how things work there.

However, as I watched the latest hype cycles in the JavaScript universe from the sidelines, I do not have many preferences when choosing "the right" technology stack. Except for one thing. I know for sure that I do not want to build serious software with JavaScript again, except when it acts as a compilation target for a more capable programming language.

So I did take a look at a couple of potential candidates: Elm, Reason, TypeScript, and F#.

Shortlist

While I respect Elm and Reason, the overall experience seemed very close to web development with F#. Which can also be used for server-side tasks (even code-sharing between client and server is possible). So out of those four, F# and TypeScript are the most serious candidates for me. Sorry Elm. Sorry Reason.

F#

Since finally crossing the chasm in 2017, I am a big fan of the language. As a long-time C# developer, it brought back the joy in programming to me. Making a case for using it in production at a larger scale project would intrigue me.

Interestingly, F# today is considered a language targeting two platforms: .NET and JavaScript. That is made possible through Fable, "a compiler powered by Babel designed to make F# a first-class citizen of the JavaScript ecosystem" – which sounds promising, doesn't it.

TypeScript

When Microsoft announced TypeScript back in 2012, tooling was poor and excitement limited. It needed a significant player in the JavaScript world, Angular, to pick it up, to gain momentum. Today it is so widely used that I consider it the de facto standard for modern web development.

Its success is driven by a powerful type system plus the fact that it is similar enough to JavaScript to keep the learning curve relatively flat. Besides support for immutable data structures, I do not miss much of what I would expect from a modern programming language.

A Small Case Study

Now, how to make an informed decision that is not solely based on gut feelings? Good question. I decided to conduct a small case study, which I designed to explore three different options to build a type-safe single page application:

  1. F# + Elmish + Feliz
  2. F# + React Function Components + Feliz
  3. TypeScript + React

In particular, I wanted to find answers to the following questions:

  1. How are parent-child relationships handled?
  2. How much boilerplate code needs to be written?
  3. How much guidance and support provides the compiler?
  4. How maintainable, aka scalable, does the approach appear to be?

The answers to those questions have already been covered in a separate post. Summary: Going with React components, either with F# or TypeScript, will make you write less code. Whereas choosing MVU (with F# + Elmish) may provide more safeguards through an architecture that is easy to understand and harder to produce errors in.

The bottom line is: Technically, all three approaches are valid, each of them has different strengths and weaknesses. So I cannot recommend one over the other. But I can introduce some more things to consider when making that choice.

More Things To Consider

Language Qualities

Code written in F# for me more often than not is concise, easy to write, and even more comfortable to read, containing only very few noisy elements. I sometimes sit in front of my computer and just look at F# code, enjoying its beauty. Seriously, that's probably what sets it apart from most other languages I've had the chance to work with. And it brings literally back the joy in programming to me. That's a factor that cannot be stressed enough, in my opinion. I firmly believe that many bored or almost burned out, but very seasoned developers could quickly be sold on it and "flipped."

Whereas TypeScript certainly has different qualities. I like how it integrates with the JavaScript world, offering its type system's help where wanted. But allowing at the same time developers to keep writing their code in the JS style they are used to. It seems to walk the line perfectly fine between the strengths of a statically-typed language and some flexibility and freedom, e.g., through supporting duck-typing. So while I personally am not a big fan of curly braces and semicolons anymore, TypeScript surely provides an enjoyable developer experience as well.

Vendor Support

TypeScript receives a lot of attention, not only from Microsoft but industry-wide. I don't see a sign that its development might slow down in the foreseeable future.

Similarily, F# has always been supported by Microsoft since its inception, and a (small) team is actively working on it. So there is no reason to worry about the future of the language itself.

However, while TypeScript is the whole package of compiler plus language, F#'s web story is a bit different. It relies on Fable as the F# to JavaScript compiler. And Fable is a complex operation which, right now, depends on only a few people's willingness to continue to work on it in their spare time (also see "bus factor" below).

Tooling

The tooling support for TypeScript is just great. For example, it integrates well in Visual Studio Code and is supported by many other editors and IDEs. Several of them are commercially supported.

The same is actually true for F#. Visual Studio (on Windows and macOS), Jetbrains Rider (on Windows, macOS, and Linux) and Ionide (on all three platforms as well) support it.

Ecosystem

For TypeScript, a large amount of JavaScript packages are supported by the community. At the time of writing, there are 6,892 packages supported alone through the DefinitelyTyped project.

Whereas the situation for Fable and F# is not that bright at the moment. There is support for a few essential players, e.g., React and Electron. But if you want to use a small random library, you most likely have to create (and maintain!) those bindings by yourself. Which is not a really complicated task – but one that steals time, which could otherwise be spent working on your own project. And if some of the maintainers of the existing bindings lose interest in them, there is a big chance you will inherit them sooner or later (again, see bus factor).

Bus Factor

The sheer number of stakeholders makes TypeScript a safe bet for most things, e.g., tooling or library support. It's not only backed and actively developed by Microsoft, but also used by major web frameworks like Angular (Google) and Vue, or at least officially supported (React, Facebook). But it's not only the impressive number of large players. The community also consists of a large number of individual contributors.

Fable, on the other hand, has a small but active community of contributors and a few companies that are backing it (e.g., through SAFE Stack). However, the key drivers of the whole ecosystem are only a dozen or so people who move the entire platform forward in their spare time.

I personally see the chance of reaching the tipping point where the ecosystem might be able to grow faster – but that's totally subjective and possibly more wishful thinking than reality.

The Pit Of Success

As described by Jeff Atwood:

The Pit of Success: in stark contrast to a summit, a peak, or a journey across a desert to find victory through many trials and surprises, we want our customers to simply fall into winning practices by using our platform and frameworks. To the extent that we make it easy to get into trouble we fail.

While TypeScript is a tool that integrates smoothly in the JS ecosystem, F# and Fable run on top of it. When using Elmish, JS is the eventual compilation target, and React is the execution layer on which the actual F# application is running without many external dependencies. Given this and the high robustness of the F# compiler plus the reliable guidance by the MVU architecture, it makes Fable and F# a poster child of the idea of the pit of success.

Whereas with TypeScript, every component might look different, depending on its author's taste and level of experience.

Talent Pool

There is no doubt that TypeScript is one of the most loved programming languages on earth at the time of writing. So it should not be complicated to find TypeScript developers or train any developer on using it.

While not at all being that popular, I think the story for F# might be more rewarding. There is a large pool of .NET developers who mainly use C# today. A language that adopted and continues to borrow more and more features from F# and that is getting more and more bloated on the way. As already mentioned: I believe that many talented and seasoned C# developers can be trained to use F#. This will make programming more enjoyable to them again and allow you to leverage their experience on the .NET platform.

Conclusion

As you can see, there are valid arguments for both TypeScript and F#. While I can and will not pick a winner at this point, I hope some information in this post can help you to make an informed decision yourself. I am sure it will be the right one! ;-)

What do you think? Drop me a line and let me know!