Specifying a Type

A type is simply a subset of all possible values in a language. For example, the type integer means all the possible integer values, but excludes lists, binaries, PIDs, and so on.

The basic types in Elixir are as follows: any, atom, float, fun, integer, list, map, maybe_improper_list, none, pid, port, reference, struct, and tuple.

The type any (and its alias, _) is the set of all values, and none is the empty set.

A literal atom or integer is the set containing just that value.

The value nil can be represented as nil.

Collection Types

A list is represented as [type], where type is any of the basic or combined types. This notation does not signify a list of one element—it simply says that elements of the list will be of the given type. If you want to specify a nonempty list, use [type, ...]. As a convenience, the type list is an alias for [any].

Binaries are represented using this syntax:

<< >>

An empty binary (size 0).

<< _ :: size >>

A sequence of size bits. This is called a bitstring.

<< _ :: size * unit_size >>

A sequence of size units, where each unit is unit_size bits long.

In the last two instances, size can be specified as _, in which case the binary has an arbitrary number of bits/units.

The predefined type bitstring is equivalent to <<_::_>>, an arbitrarily sized sequence of bits. Similarly, binary is defined as <<_::_*8>>, an arbitrary sequence of 8-bit bytes.

Tuples are represented as { type, type,… } or using the type tuple, so both {atom,integer} and tuple(atom,integer} represent a tuple whose first element is an atom and whose second element is an integer.

Combining Types

The range operator (..) can be used with literal integers to create a type representing that range. The three built-in types, non_neg_integer, pos_integer, and neg_integer, represent integers that are greater than or equal to, greater than, or less than zero, respectively.

The union operator (|) indicates that the acceptable values are the unions of its arguments.

Parentheses may be used to group terms in a type specification.

Structures

As structures are basically maps, you could just use the map type for them, but doing so throws away a lot of useful information. Instead, I recommend that you define a specific type for each struct:

 defmodule​ LineItem ​do
  defstruct ​sku:​ ​"​​"​, ​quantity:​ 1
  @type t :: %LineItem{​sku:​ String.t, ​quantity:​ integer}
 end

You can then reference this type as LineItem.t.

Anonymous Functions

Anonymous functions are specified using (head -> return_type).

The head specifies the arity and possibly the types of the function parameters. Use “. . .” to mean an arbitrary number of arbitrarily typed arguments, or a list of types, in which case the number of types is the function’s arity.

 (... -> integer) ​# Arbitrary parameters; returns an integer
 (list(integer) -> integer) ​# Takes a list of integers and returns an integer
 (() -> String.t) ​# Takes no parameters and returns an Elixir string
 (integer, atom -> list(atom)) ​# Takes an integer and an atom and returns
 # a list of atoms

You can put parentheses around the head if you find it clearer:

 ( atom, float -> list )
 ( (atom, float) -> list )
 (list(integer) -> integer)
 ((list(integer)) -> integer)

Handling Truthy Values

The type as_boolean(T) says that the actual value matched will be of type T, but the function that uses the value will treat it as a truthy value (anything other than nil or false is considered true). Thus the specification for the Elixir function Enum.count is

 @spec count(t, (element -> as_boolean(term))) :: non_neg_integer

Some Examples

integer | float

Any number (Elixir has an alias for this).

[ {atom, any} ]
list(atom, any)

A list of key/value pairs. The two forms are the same.

non_neg_integer | {:error, String.t}

An integer greater than or equal to zero, or a tuple containing the atom :error and a string.

( integer, atom -> { :pair, atom, integer } )

An anonymous function that takes an integer and an atom and returns a tuple containing the atom :pair, an atom, and an integer.

<< _ :: _ * 4 >>

A sequence of 4-bit nibbles.