Elixir est un langage à typage dynamique, ce qui signifie qu'il ne vérifie pas les types à la compilation. Les spécifications de type restent toutefois utiles, car elles :
On peut ajouter une spécification de type à une fonction à l'aide de l'attribut de module @spec, juste avant la définition de la fonction.
@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
def longer_than?(string, length), do: String.length(string) > length
Expressions autorisées dans une spécification de type :
Types de base, par exemple :
boolean()integer(), non_neg_integer(), pos_integer(), float()
list()map()any()Une union de types :
integer() | list(integer())
Des types paramétrés :
list(integer()), une liste d'entiers%{age: integer()}, une map avec une valeur de type entier sous la clé :age
Des types distants (définis dans un module), par exemple :
Des littéraux, par exemple :
%{}, une map vide[], une liste vide (mais [any()] est une liste non vide):ok, un atomeDes types spécialisés intégrés, par exemple :
char(), un entier dans l'intervalle 0..0x10FFFF
charlist(), une liste de caractèreskeyword(), une liste de tuples de deux éléments, dont le premier élément est un atomeDes types personnalisés
La liste complète de tous les types se trouve dans la section « Typespecs » de la documentation officielle.
Il est également possible de nommer les arguments dans la spécification de type, ce qui est utile pour distinguer plusieurs arguments de même type.
@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()
On peut définir des types personnalisés à l'aide de l'un des trois attributs de module :
@type : définit un type public@typep : définit un type privé@opaque : définit un type public dont la structure est privée@type color :: {hue :: integer, saturation :: integer, lightness :: integer}
@spec to_hex(color()) :: String.t()
String.t() vs binary() vs string()
String.t() est le type correct à utiliser pour les strings Elixir, qui sont des binaires encodés en UTF-8. Techniquement, String.t() est défini comme un binary(), et ces deux types sont équivalents pour les outils d'analyse, mais String.t() est le choix le plus révélateur de l'intention pour documenter des fonctions qui manipulent des strings Elixir.
En revanche, string() est un type différent. C'est une string Erlang, appelée charlist en Elixir. Il faut éviter le type string() dans les spécifications de type et utiliser charlist() à la place.
Dialyzer est un outil d'analyse statique qui peut détecter des problèmes tels que des erreurs de type dans du code Erlang et Elixir. La façon la plus simple d'utiliser Dialyzer dans un projet Elixir est d'avoir recours à Dialyxir.