The Power of Elm in JavaScript

Since first learning of Elm, I’ve only heard good things. I’m convinced Elm could become the future of front-end development in the coming years. Here are some blog posts in the Elm community that have particularly stuck out to me:

For the moment, I'm not involved in any Elm project. However, I’ve been messing around with Elm a bit, and I watched some Elm Daily Drip videos. I am working on some JavaScript projects, specifically this React Project. I want to work with Elm more, and I know Elm can bring some incredible things to front-end development.

How can I bring these things to JavaScript, since I am just working with JavaScript presently?

Let's see first what Elm can do for us, as developers.

Why Should I care about Elm ?

This is a common question people ask themselves, and there is a book called Why Elm from O’Reilly.

In this book, they say:

Many of the common issues that front-end developers have to deal with just don't exist in Elm.

YES! You read it well. They simply don't exist. Imagine yourself not dealing with undefined is not a function or odd things like: NaN === NaN. Some of these weird things have an explanation, but they are still weird.

Elm compiler

Elm has an awesome compiler. Imagine you have a compiler as an assistant.

Elm ensures that errors will happen at compile time, in front of a developer, instead of runtime, in front of a user. - Why Elm

The Elm compiler is awesome Let’s look at one example:

In this example, we were trying to return a String and a number in our if/else. The compiler makes your life easier, explaining to you exactly what the error was and what you can do.

Now, imagine you made a typo. Rather than typing map you typed nap.

The compiler explains to you what you did and gives you a few options.

Total immutability

Imagine you don't need to worry about mutable state in your application. Everything is immutable.

Purely Functional

Elm is a purely functional language. This means you can use all the power of Functional Programming in your code.

Here are some good articles talking about FP.

Reactive Programming

In imperative programming languages, we have:

let a = b + c

If we change the value of b, a will not be updated. Elm helps us to have that by computing values from the state.

Strong Static Types

The use of types is one of the main points of using Elm. With strong static types, Elm can infer the types of each variable or function. It prevents a series of mistakes you can make.lso, we don't need to worry about null or undefined. Elm has a solution for this.

Bringing these things to JS

We saw what Elm is best used for. Let's see how we can bring these things to JavaScript, if it's possible.

Static Types

There are a few ways you can bring something like static typing to JavaScript.

Flow

We are using Flow in the Formulae project.

Imagine you have a function, and you have used an undeclared variable.

function myFunction() {
  let a = b;
}

Flow will explain that you have used an undeclared variable.

➜  formulae_react git:(master) ✗ flow status
src/output_lib/decoders.js:199
199:   let a = b;
            ^ identifier `b`. Could not resolve name
Found 1 error

Now imagine you have a function that receives only a number, what if you pass a string to it?

function timesTwo(x: number) {
    return x * 2;
}

function main() {
    timesTwo("hello");
}

Flow says the type is incompatible with the expected parameter we created.

➜  formulae_react git:(master) ✗ flow status
src/output_lib/decoders.js:203
203:   timesTwo("hello");
^^^^^^^ string. This type is incompatible with the expected
param type of
198: function timesTwo(x: number) {
                    ^^^^^^ number

Found 1 error

These little things can help you a lot in your development phase.

TypeScript

TypeScript has a lot of interesting features. We find people all over the web talking highly about it. Personally, I prefer using Flow, so I'm just mentioning TypeScript here. If you think it's good, go for it!

Redux

For those who work with React, Redux is based on the Elm architecture. So, if you are already using Redux, you are using something Elm-based, and you never thought about it.

We are using Redux and we like it!

If you check a simple structure of a program in Elm, you can see we have a Model, a function to update and the view. This is very similar to redux.

import Html exposing (..)


-- MODEL

type alias Model = { ... }


-- UPDATE

type Msg = Reset | ...

update : Msg -> Model -> Model
update msg model =
    case msg of
    Reset -> ...
    ...


-- VIEW

view : Model -> Html Msg
    view model =
    ...

Redux First Router

Another thing we think is good is Redux First Router. We are not using it on the project I mentioned earlier, but we liked the idea of having routing state being just another part of the application state.

In our store, we can define all the routes we have:

...
const routesMap = {
  HOME: "/", // action <-> url path
  PRODUCT: "/product/:id" // :id is a dynamic segment
};
...

These actions will be used in the Reducer, we can change the state once we change the route.

const productsReducer = (state = init(), action = {}) => {
  switch (action.type) {
    case "HOME":
      ...
    case "PRODUCT":
      ...
      ...

Handling routing in elm via navigation is basically the same thing.

Decoders

Elm uses a layer called Decoders, it is a boundary between your front-end and your back-end. We can see this in other languages, but Elm does this very explicitly. In our JavaScript code we created Decoders from the data we received and we created Encoders to the data we send.

As we are using ImmutableJS, we convert the JSON we receive into our own app types. With this, our app now recognizes weird JSON structures easily, and we also add a new validation phase in getting data from our API.

Let's imagine we have an API for Person. Once we receive the data from our server, we call the decode function and its responsibility is to return a PersonType.

const Person = {
  get: (name: string): Promise<PersonType> => {
    return api.get(`${name}`).then(resp => decodePersonType(resp.data));
  }
};

In our case, our PersonType is an immutable Record.

import { Record } from 'immutable'

export default class PersonType extends Record({
  name: '',
  age: 0,
  github: ''
}) {
  name: string
  age: number
  github: string
}

In our code, we have an ApiPerson type.his maps exactly to the JSON we will receive.

  type ApiPerson = {
    name: string,
    age: number,
    github: string
  }

  decodePersonType(person: ApiPerson) : PersonType{
    return new PersonType({
      name: person.name,
      age: person.age,
      github: person.github
    })
  }

Our decode function converts the Api type, ApiPerson to our PersonType.

Summary

Now you know what are the the good things Elm can bring us. If you can only work in a JavaScript project, you can probably bring some of these Elm feature for your JavaScript code.

Resources