neurodynamic
neurodynamic

Reputation: 4404

When to use type alias vs. single-value union type in Elm

I've been reading over Richard Feldman's Elm SPA app example, and I'm seeing a number of examples of things like this:

type Username
    = Username String

and I'm not sure when it makes sense to use something like that, a single-value union type, vs. just a type alias like this:

type alias Username
    = String

When is it appropriate to use a single-value union type vs. just using a type alias?

Upvotes: 3

Views: 698

Answers (1)

Chad Gilbert
Chad Gilbert

Reputation: 36375

There is no hard and fast rule for when it is appropriate, but I tend to follow a few rules of thumb. Let's use an authenticate function example that takes a username and password, both of which are string values.

At a bare minimum, without any additional alias or types, the annotation could be this:

authenticate : String -> String -> Bool

Given that annotation, it isn't clear which parameter is the username and which is the password. We can improve the readability by using type aliases:

type alias Username = String
type alias Password = String

authenticate : Username -> Password -> Bool

This is better for consumers of my package but type aliases won't disallow you from accidentally swapping the parameters in calling code. For example, this problematic function would compile:

login : Username -> Password -> Bool
login username password =
    if authenticate password username then ...

If you want to go a step further and force the explicit declaration of the type every time you use it, you could avoid that type of error because the compiler will catch mixups:

type Username = Username String
type Password = Password String

With that definition, you must now explicitly unwrap and package the strings in either a Username or Password constructor every time you use it. This is especially useful for things like units of measure, where such a concept could have avoided the loss of a Mars mission

As you see in Richard's example, going the route of a full type and type constructor means you'll need separate boilerplate functions for json decoding, encoding, etc, which can get tedious. You'll need to find the right balance for your team and projects.

Upvotes: 8

Related Questions