How to add .t() types for ecto schemas / Handling credo warnings

I have the following context:

defmodule Foo.Companies.Company do
  use Foo.Schema

  schema "companies" do
    field :name, :string

    belongs_to :organization, Foo.Organizations.Organization

    timestamps()
  end
end

Somewhere else I have a function like this:

  @spec do_foo(%Company{}) :: :ok
  def do_foo(%Company{} = company) do
    ...
  end

This seems to work fine, but when I run mix credo I get the following warning:

┃ [W] → Struct %Company{} found in @spec

Upon expanding the warning with mix credo explain ... it says that I should be using something like Company.t() in the type spec instead of the struct directly.

My question is: What is the preferred way of adding such a type to a struct generated by an Ecto schema? I could add something like:

  @type t :: %__MODULE__{
          name: String.t(),
          organization_id: non_neg_integer()
        }

but it seems a bit strange to have to do that manually. Is there a better way? Besides having to do it manually, I see the following problems with the type I just defined:

  • It doesn’t capture the fact that a Company can sometimes also have a organization associated with it. Some functions that take a %Company{} might require this organization to be preloaded, while others might not.
  • It doesn’t capture the fact that there are timestamps in the struct.
  • If I change the schema I also have to change this type manually.

What are best practices for combining credo dialyzer and ecto like this?

You don’t have to do it manually, it’s already there. Just do @spec do_foo(Company.t()) :: :ok.

Are you sure? That’s not what the documentation says, I think? mix dialyzer also tells me that it can’t find the type when I try.

Yeah, ecto doesn’t define types, because it has no idea about types for fields, especially around custom ecto types. This requires manual maintenance, but afaik there are also some third party libraries trying to automate that.

The company I used to work at must have been using such a library. Sorry @munksgaard, I really shouldn’t have answered as I haven’t used typespecs lately. My bad :grimacing:

1 Like

No hard feelings my friend, I appreciate the effort :slight_smile:

1 Like

Aha, I see that e.g. typed_ecto_schema is trying to address this issue.

2 Likes