W0083 - Type definitions should live in modules, not header files
Warning
%% my_types.hrl
-type user_id() :: binary().
%% ^^^^^^^ 💡 warning: Type definitions should live in modules, not header files.
Explanation
This diagnostic fires on type definitions — -type, -opaque and -nominal —
declared in a header file (.hrl).
A header is textually included, so a type defined there is redefined in every
module that includes it. There is no single module that owns the type, nothing
to -export_type it from, and no way for a caller to refer to it as
module:type(). -opaque in a header is worse still: every including module
gets its own copy, so the opacity it promises is not enforced anywhere.
Fix
Define the type in a module and export it:
%% my_types.erl
-module(my_types).
-export_type([user_id/0]).
-type user_id() :: binary().
Callers then refer to it as my_types:user_id(), with one definition and one
owner.
Note that records are not affected by this diagnostic — -record declarations
in headers remain the normal way to share a record between modules.