From JavaScript to TypeScript to Elm

In this article, I will cover my migration progress between all three languages and explain why and what brought me to move over.

I hope I will shed some light and convince some of you to try out a new language for the sake of your software and its reliability.

Javascript

Anybody who has written javascript in their life has already faced far too many times one of those following generic errors:

Initially, many of us begin their journey with javascript as they need to add some “simple” features to some website. Some will use libraries like jQuery, Lodash or Underscorejs.

Eventually, as you grow up you will start to develop bigger web applications and those become more complex, so you will turn to a framework like Angular, Vuejs or Reactjs.

Maybe you have a different path and you come from a more backend experience. Nowadays, NodeJS has become a very popular choice for backend applications and allows you to write in… yeah, javascript.

Whichever from where you come, you’ve seen it, and you are probably still doing it, writing javascript code that eventually shows up one of those errors shown above.

Why Javascript is actually an okay language for supportability

The main problem with Javascript is that the language has to support backward compatibility. There is no “version” with javascript like some other languages (ex: Java7 -> Java8).

Because the language has been essentially written for web browsers initially, the language is built to always work as long as browsers support the standards of the language. This basically allows a website written in the 1990s to still work today in your fresh new Chrome version, even if the code that was written is basically 30 years old.

Browsers eventually catch up and support more new functionality of javascript that eases the life of the developers, but it still supports backward compatibility so that this really old website continue to work. This is the source of all evil because, for the sake of supporting older code, the language cannot make any breaking changes that would change how things are done for the greater good.

That being said, if you do write an application for a web browser, odds are this app will be functional forever.

Why Javascript is a horrible language for maintainability

Now you might ask if it’s so good because things will work forever, why did I move from Javascript to Typescript?

Javascript is, like the name says, a scripting runtime programming language, meaning that anything you write will always run. And that is, whether you wrote good or bad scripts.

Javascript is known to crash at runtime, because well, you often end up writing pieces of code that do not ensure if everything is good. This usually starts happening more as you interact with external API’s. It’s pretty hard to be always on top of things and protect every single line of code you write and verify if it’s not null or undefined.

The problem with that is, that it crashes, and it crashes in the worst way: Runtime crashes. This means, it’s your end users that discover those errors, not you.
If you had planned to create a reliable and nice-to-use web app, then using javascript won’t help you maintain your application for a long time as errors will eventually start showing up, and you won’t know about them. Your users will face those errors and you will need to debug every single one of them to understand where that null or undefined came from.

How using Typescript solve some of those issues

Typescript is a superset language of Javascript.

Put simply, it extends Javascript allowing you to write anything possible in Javascript, but with the ability to use the ecosystem built by Typescript.

One of the thing that you will benefit immediately from Typescript is the compiler. Typescript will warn and prevent you from compiling your typescript code to javascript code.

Typescript is capable of a few things as of version 3.2, such as :

  • Protect you from possible null or undefined objects
  • No unused parameters or variables
  • Verify the integrity of your conditions and if you have properly checked an object for a certain state

Such things will prevent minor errors, and the compiler will catch those issues for you. You should get fewer runtime errors if you can hand-out the job of checking those type of issues to Typescript.

The problem with that is, that it crashes, and it crashes in the worst way: Runtime crashes. This means, it’s your end users that discover those errors, not you.
Another really good part of Typescript is, it’s typing system, something that does not exactly exists in Javascript.

Typing variables allow Typescript to identify if the object or variable is of the right type.

let n: number = 0;
n = “a”; // Typescript will not allow that, as this is attempting to convert a number type to a string.

Using types across your code allow the compiler to know more about your code and help you out. This will ensure that your code is properly maintained and follow strict guidelines for better predictability of the functionality.

Here’s an example of Javascript vs Typescript and how the type system comes to save us in this case:

// Javascript
var a = “test”;
a = 0;
// Because of the last line of code, this will never reach.
// Javascript wont tell you anything about it either, you will realize it at runtime that something is off
if (a === “test”) { 
 runSomeVeryImportantFunction();
}
// Typescript
let a: string = “test”;
// Typescript will raise an error and prevent you from doing this assignation. 
// The compiler protected here what could’ve been a runtime error.
a = 0;
if (a === “test”) { 
 runSomeVeryImportantFunction();
}

This is a very simple and generic example, but as your application grows, you eventually run down in those simple errors because things get out of control. If you can rely on the compiler to protect you from those errors, then you will have a lot fewer runtime errors.

The bad parts of Typescript and why I moved to Elm

Typescript offers many great things like a Type safety system, a better OOP centered system (classes and objects) and basically powers up Javascript to a whole new level.

But it’s still, a superset that supports 100% of what Javascript can do, and that is, the problem of Typescript. Due to that, the code is always prone to unsecured types, the developer will eventually forget to properly type their things and will let slip errors here and there. It still does not protect you from external API changes and every variable in the system are mutable… which is one of the biggest cause of issues.

You are held responsible as a developer to seek external modules to help you out with things like bundling, state management, minifying, etc.

We run a pretty elaborated NodeJS server all written in typescript where I work, and we use advanced types and enums all over the place in order to ensure we are as safe as possible, and it works okay. We have all the strict flags on, making sure our code is as strictly typed as it can from Typescript perspective.

The problem with that is, that it crashes, and it crashes in the worst way: Runtime crashes. This means, it’s your end users that discover those errors, not you.
Typescript also allows you to cheat, using the any type, you can basically skip all type check and tell typescript that a certain piece of code can do anything. Those are very easy to use when you don’t want to comply with the system and many use that as an easy exit door to get their feature done faster.

My experience with Typescript is great, it’s a very good bridge from a Javascript enthusiast (and an easy one to cross) as you feel at home immediately. If you use the type system correctly, you will be able to gain more support from the compiler, but that is If you do so. The language will not force you to comply and you can always run away from it.

Typescript does not protect you from side effects, which affect state mutability. I’ve had several hard to track issues with Angular and React causes by data mutability.

Typescript will allow you to write ES6+ functions and compile it to a lower-level Javascript version so that it has better support across the browsers, which is also another nice thing.

So what is Elm and how or why is it better than Typescript?

Let start with one thing: Elm is a functional language, and if you have never touched one before, this is going to be a big step going in.

Elm is a language that compiles to Javascript, just like Typescript, but it’s a whole new language that does not try and make compromises.

The problem with that is, that it crashes, and it crashes in the worst way: Runtime crashes. This means, it’s your end users that discover those errors, not you.
It is a language that once data is in its system, nothing can ever be in a state of null or undefined. Things will always have a value, and the system will never crash because things have their proper type as well.

Elm comes with Data Immutability right out of the box, Bundles and Minify code for you, and most importantly, it Enforces type safety, preventing developers to try and cut corners. It is very fast and very lightweight.

If you are concerned, the output can be embedded in any web page easily, so it’s not that hard to get started with a small trial if your project is immense (You don’t need to convert all your code to elm to embed it).

It has an advanced typing system that allows you do to even more, which I will cover entirely in another blog post.

Because elm is a functional language, you cannot get into a weird state caused by side-effects and your code is very easily testable. Functions you write will always return exactly the same result given the same input data.

Because you can so heavily depend on the Elm compiler, updating and refactoring pieces of code is an absolute breeze. The compiler will complain for quite a bit of time, but the moment it stops from doing so, you are good to go. No need to test anything, simply follow the compiler guidance about each error he finds and your code will all start working again once you have done so. This experience really gives you a good confidence level in your software even after destroying it apart and rebuilding it. (Which normally, you would be unsure if you have missed something somewhere)

The Elm Architecture (TEA)

Elm has what it calls its own architecture that some project is based on (Redux). It’s very pleasant to work in TEA, things are straight forward and a lot easier to manage. It does an extremely good job at separating the logic from the rest, which comes in nice when testing your code.

Because the language is built that way, all developers are forced to follow that pattern and to be strict about anything they create. There is no such thing as any in elm, and thus, every contributor is forced to properly write code. The result is quite simple: Better code, better maintainability, no runtime errors.

Elm will force you to handle all the cases all the time, which in a way, has a strain on you as a developer, but a good one. If you do an API call as an example, then you must handle the cases of Failure, Success and Loading, but the end result is that all those handled case will give not only a better understanding of what is going on to the user but also no errors in case something bad happened (which you might not normally write code to cover that case in Typescript).

The hard part going into Elm

Coming from a background of C++, C#, Java, Typescript, Python, I am more than used to write loops (While/For) and when you get to a functional style language, there is no such thing. You must use functions such as Map, Fold, Filter and more, and that is how you manipulate your data when you want to loop. I found it hard initially to get used to that.

The problem with that is, that it crashes, and it crashes in the worst way: Runtime crashes. This means, it’s your end users that discover those errors, not you.
Elm is a completely different language, it took some time to learn it and you will have to work hard as well to understand the new keywords and patterns of that language. A good place to start is at ElmProgramming.

Writing Encoders and Decoders initially are a complex task and feel long to do, but it’s because of those that elm is capable of ensuring your data is always safe and validated before going into the elm machine. The compiler is capable of ensuring input and output data are always safe because of those. You must take the proper time to learn how to create them and use them.

Elm does not allow you to save anything by yourself. You do not create variables. You simply pass back your whole new model and elm takes care of saving that model for you in memory (Because that is an unpure method to do). This was for me, hard initially to grasp because I was used to keeping data in a class as a class parameters (a private variable as an example). This makes it so that you only have one state that is saved, and that state is your main model, which you can manipulate and change the way you want it. It’s just, hard to change your way of dealing with code.

Give it a shot, upgrade your codebase to a language that will help you along the way

If you are still writing Javascript, you should seriously consider upgrading to Typescript. It will help you a lot to reduce runtime errors, and those who want even more protection and reliability, should consider trying Elm and see how they like it.

I will be honest, I have never had so much fun writing code. Elm is just very well built, and building a web app with this language makes the job a lot more enjoyable to do.

We push updates to our online cloud platform on production on a daily/weekly basis, and that is not a big deal for anybody. If the compiler compiled your code, you know, nothing is broken. Run some tests, and we are good to go to deploy that code.

The only errors you will get in Elm are going to be logic errors, but those are caused by you, the developer who did not think his things right.

I hope this will help some developers move along in their code and use better languages/tools to support their web apps in a more reliable and enjoyable way.

#javascript #typescript #web-development

From JavaScript to TypeScript to Elm
75.25 GEEK