loading...

How a Type System Improves your JavaScript Code

iwilsonq profile image Ian Wilson Updated on ・3 min read

Vanilla JavaScript is untyped by nature, some will call it “smart” because it is able to figure out what is a number or a string.

This makes it easier to run JavaScript code, it simply needs to be executed in a browser or Node.js runtime. However, its vulnerable to numerous runtime errors that can spoil your user experience.

If you’ve ever experienced the following, you would benefit from adopting a type system.

  • After fetching a list of data you may find that a certain field doesn’t exist on one of the records, causing the app to crash unless explicitly handled.
  • An instance of a class you imported doesn’t have a method you’re trying to invoke.
  • Your IDE doesn’t know what methods and properties are available, so it cannot easily assist you with autocomplete.
  • Difficulty reasoning about code, type systems at a glance make it easier to refactor

Flow, TypeScript, or ReasonML

Let's say you have an existing codebase that you wish to make bulletproof. With respect to type errors, you could try adopting Flow or TypeScript -- they have a fairly similar syntax.

On the other hand adopting one of these in a large, existing codebase is difficult. You would have a backlog crammed with tasks relating to creating types and interfaces with code that made not have been designed in a type friendly way.

On top of all of this, Flow and TypeScript do not offer 100% type safety in their code.

Reason accomplished perfect type safety through inference, and makes annotating variables and function signatures much more straightforward.

Simple and Clearly Contrived Examples

Consider the following code:

let add = (a, b) => a + b;

In basic JavaScript these arguments can be numbers or strings. In TypeScript or Flow these arguments can be annotated like so

let add = (a: number, b: number) => a + b

The first code snippet knows that we are adding two int values. Not two floats nor two strings, there are different operators for those addition operations. JavaScript can hardly tell the difference between an int and a float.

Allow me now to expose this gradual typing with a contrived example.

let add = (a: string, b: number) => a + b
add('some string', 5) // outputs: "some string5"

That function works! This is absolutely preposterous! Now how does Reason handle this?

let add = (a, b) => a + b;
add("some string", 5);
/*
This has type:
  string
but somewhere wanted:
  int
*/

This function was flawed at the implementation level. Reason has different operators for int, float, and string addition.

The purpose of this contrived example was to show that it is still very possible to have odd type "errors" even though it wont break the application.

In a pure Reason program, developers will not have to deal with productions bugs that have to do with types or null values.

Developer Experience

One of the neatest features of TypeScript is the enhancement you get in code editor suggestions & autocompletion.

This is one area where TypeScript has a leg up on Reason, because a TypeScript program doesn't need to compile perfectly in order to offer autocompletion. Reason makes you fix errors in syntax or types before it gives you helpful autosuggestion.

This is the case on VSCode, but I know many Reason developers use vim. I cannot answer for the level of support each editor has.

Even though I am a big fan of ReasonML, I have built production applications with TypeScript or Flow and I enjoy them as well. The wave behind TypeScript makes it especially good to pick up these days, considering there is plenty of writing and community support behind it.

Reason on the other hand is harder to pick up because there is comparatively less writing and content behind it. Through blog posts like this, I am hoping to change that.

If you have some interest in checking out Reason, I'd start with the docs here. Also, be sure to follow people like @jordwalke, @jaredforsyth, and @sgrove on twitter. They are pretty knowledgable with respect to the ReasonML/OCaml ecosystem.

If you want to how ReasonML works seamlessly with GraphQL, check out this article I wrote on ReasonML with GraphQL, the Future of Type-Safe Web Applications.

If you'd like to keep up with future posts, sign up for my newsletter here!

Posted on Sep 13 '19 by:

iwilsonq profile

Ian Wilson

@iwilsonq

I mostly just code or run. Aside from programming I'm generally training for a marathon.

Discussion

markdown guide
 

I still like writing plain old Javascript like we did in the good old days, but when I work with 50 people in 3 timezones on a large project, I currently prefer typescript (the tooling is really a differentiator).

 
  • Original JavaScript with traditional programming is very exciting. Moreover, just using Notepad ++ is more festive for us just as a casual hobby.
  • With TypeScript, React or Flow it is possible that we cannot execute directly with our browser but must be compiled first. And the end result is an enlarged file.
  • Likewise with various libraries like jquery, underscore and others we don't understand the original syntax of javascript itself.
  • The library as a tool is really needed like Codemirror, Mathjax, Katex.
  • Maybe for developers who are tied to tasks that require high productivity, certainly Typescript, Flow, React, jquery, undersore can help increase productivity.
  • But if we are only as experimentalists or as hobbies, we recommend experimenting with Original Javascript with traditional programming.
  • Three reference mainstays that we can use are: MDN, W3Shool and Stackoverlow.
  • This is my opinion, and your thoughts and yours must be different from mine.
 

My appreciation for TypeScript grew out of maintaining the same two JavaScript projects over a 5 year period. Writing POJS is fine, but if your project doesn't have a finite scope, or you have multiple contributors, the additional structure provided by types pays huge Dividends in the long term.

 

While a type system won't improve my personal code it would drastically improve team productivity and code maintenance burdon when someone else needs to maintain my code. Basically from hell to heaven, tooling, early error check. Code can be good either way, maintenance definitely not.

 

We have this habit of beating around the JavaScript bush using transpilers to hide its non-classical behavior. I have trouble justifying the extra build step just to arrive back at good ol' js.

 

Yep, I definitely wouldn't recommend it for every single project, especially not when working through an experiment or proof-of-concept. Static analysis can be a bit tiring but it gets stronger as the codebase increases significantly.

 

I could definitely see where JavaScript could become unwieldy in larger projects. For people who've learned class based languages, typescript offers a great abstraction from js oddities.

 

Try Nim lang, better types and compiles to JavaScript.