Typespec for Enumerable

It depends what you want to do with the type specification. If it should be a help for the reader or programmer, than you can define your enumeration type for your API, e.g. something like

@opaque my_enum(t) :: list(t) | Enum.t

This compiles, reveals no details about the internal of type (thus @opaque) and you communicate your intention. But the dialyzer cannot help at finding type errors. The following snippet is wrong, but dialyzer does not complain:

  @opaque my_enum(t) :: Enum.t | Enumerable.t | list(t)

  @spec take_ten(integer) :: my_enum(integer)
  def take_ten(max) do
    max
    |> Stream.unfold(fn 0 -> nil; n -> {n, n-1} end)
    |> Stream.take(10)
  end

  @spec ten_ints() :: list(atom)
  def ten_ints() do
    take_ten(20) |> Enum.to_list()
  end

I assume that it comes from type union. It could be a list of atoms, because the stream functions are allowed to return enumerable of any type. And you cannot use Enum.t(integer) because it is not defined in the Enum module. This could be an interesting bug report and PR for the Enum module, because you could define type t this way:

@type t :: t(any)
@type t(x) :: Enumerable.t(x)

You need to specify properly all enum functions to take parameterized types. But I am unsure how the type definition on the protocol level works, in particular since Enumerable.t is not defined explicitly but seems to generated by defprotocol.