Phantom types are types that have a type variable on the type that is not used constructors. E.g.
type Users a = Users (List User)
This type variable allows us to restrict what type a function can take and return. For example:
type Active = Active activeUsers : List User -> Users Active activeUsers users = users |> List.filter isActive |> Users
activeUsers is a function that takes all users and only returns active users.
Phantom types are useful for things like:
- Enforcing invariants in functions and views
- State machines
In the example below we could have a view that only takes active users:
usersView : User Active -> Html msg
The compiler will complain if we try to pass all users to this view. In this way it can be sure that we are filtering users correctly.