Closed wkhere closed 10 years ago
We can't import types because they are not available to us at that point. import
only works for functions and macros. You have to reference the remote type with it's module name (which can be aliased).
Thx for the explanation. Is there any remote possibility it will change in the future?
It's a technical limitation that I don't think we can work around (I could of course be wrong). Unfortunately types are not available to us for modules loaded during compilation.
It could potentially be fixed, if we wanted, by storing the type information but I am not really sure if we should. Maybe by an implicit import type directive, I wouldn't mix it with the regular import though, since it increases the chances of conflicts and so on.
Any chance this might get implemented after all these years? or it is a topic to be closed?
Example:
@type html_tree :: Floki.html_tree
Simply redeclare types you would like to use without a module name.
The topic is closed but I am writing this as a tip for who would still search the topic.
Posting a (probably hacky) solution because this was driving me nuts too.
defmodule Types do
@moduledoc """
Common type helpers for typespecs.
"""
@type_strings %{
user_id: """
@typedoc "The primary key for a `user` record."
@type user_id :: Ecto.UUID.t()
""",
user_surrogate_id: """
@typedoc "An additional identifier for a `user` typically created by the client."
@type user_surrogate_id :: Ecto.UUID.t() | String.t()
"""
}
@doc """
This macro is to be called with a list of atoms. Each atom refers to a string representation of a type definition present in
the `@type_strings` module attribute. The types will be defined in the calling module.
"""
defmacro import_types(types) do
ast =
types
|> Enum.reduce([], fn type, strings ->
[Map.fetch!(@type_string, type) | strings]
end)
|> Enum.join("\n")
|> Code.string_to_quoted!()
quote do
unquote(ast)
end
end
end
defmodule Foo do
import Types, only: [import_types: 1]
import_types [:user_id, user_surrogate_id]
@spec foo(user_id(), surrogate_id()) :: String.t()
def foo(user_id, surrogate_id), do: "#{user_id}-#{surrogate_id}"
end
Simplest example:
Elixir 0.14.3
(of course in the real world equivalent of Foo is not only used for defining types).