Ecto is an external library and would not have a t
function defined. The t
type is, by convention, added for your own structs. For example, in a User
module you might have the following from the docs:
@type! t :: %User{name: binary, age: integer}
This can then be used at a callsite as…
@spec! my_fun(User.t()) :: User.t()
This allows you to ensure that a received argument is not only a User
struct, but also that its name is a binary and age is an integer.
If you didn’t care about requiring those types, this would also work…
@spec! my_fun(%User{}) :: %User{}
This tells you that you can do the same with any struct. So in the case of a changeset, you can use…
@spec! fun(%Ecto.Changeset{}) :: %Ecto.Changeset{}
As an example, you can even make your own custom types such as this one:
@type! error_changeset() :: {:error, %Ecto.Changeset{}}
This can be used at the callsite with…
@spec! fun(%Ecto.Changeset{}) :: error_changeset()
In practice, I’ve found that I need only a handful of custom types (other than t
definitions). The library provides you with most of the builtins you would expect with regular typespecs.