TypedStructor (TypedStructor v0.6.1)

Copy Markdown View Source

Installation

Add :typed_structor to your dependencies in mix.exs:

def deps do
  [
    {:typed_structor, "~> 0.6"}
  ]
end

Formatter Setup

Add :typed_structor to your .formatter.exs for proper indentation:

[
  import_deps: [..., :typed_structor],
  inputs: [...]
]

Getting Started

Use typed_structor blocks to define fields with their types:

defmodule User do
  use TypedStructor

  typed_structor do
    field :id, pos_integer(), enforce: true  # Required, never nil
    field :name, String.t()                  # Optional, nullable
    field :role, String.t(), default: "user" # Has default, not nullable
  end
end

Nullability Rules

The interaction between :enforce, :default, and :null determines whether a field's type includes nil:

:default:enforce:nullType includes nil?
unsetfalsetrueyes
unsetfalsefalseno
set--no
-true-no

You can set :null at the block level to change the default for all fields:

typed_structor null: false do
  field :id, integer()                         # Not nullable
  field :email, String.t()                     # Not nullable
  field :phone, String.t(), null: true         # Override: nullable
end

Options

Opaque Types

Use type_kind: :opaque to hide implementation details:

typed_structor type_kind: :opaque do
  field :secret, String.t()
end
# Generates: @opaque t() :: %__MODULE__{...}

Custom Type Names

Override the default t() type name:

typed_structor type_name: :user_data do
  field :id, pos_integer()
end
# Generates: @type user_data() :: %__MODULE__{...}

Type Parameters

Create generic types with parameter/1:

typed_structor do
  parameter :value_type
  parameter :error_type

  field :value, value_type
  field :error, error_type
end
# Generates: @type t(value_type, error_type) :: %__MODULE__{...}

Nested Modules

Define structs in submodules:

defmodule User do
  use TypedStructor

  typed_structor module: Profile do
    field :email, String.t(), enforce: true
    field :bio, String.t()
  end
end
# Creates User.Profile with its own struct and type

Plugins

Extend TypedStructor's behavior with plugins that run at compile time:

typed_structor do
  plugin Guides.Plugins.Accessible

  field :id, pos_integer()
  field :name, String.t()
end

See the Plugin Guides for examples and instructions on writing your own.

Documentation

Add @typedoc inside the block, and @moduledoc at the module level as usual:

defmodule User do
  @moduledoc "User account data"
  use TypedStructor

  typed_structor do
    @typedoc "A user with authentication details"

    field :id, pos_integer()
    field :name, String.t()
  end
end

Summary

Functions

Defines a field in a typed_structor/2. You can override the options set by typed_structor/2 by passing options.

Defines a type parameter in a typed_structor/2.

Registers a plugin for the currently defined struct.

Defines a struct with type information.

Functions

field(name, type, options \\ [])

(macro)

Defines a field in a typed_structor/2. You can override the options set by typed_structor/2 by passing options.

Example

# A field named :example of type String.t()
field :example, String.t()

Options

  • :default - sets the default value for the field
  • :enforce - if set to true, enforces the field, and makes its type non-nullable if :default is not set
  • :null - when set to true (the default), allows nil to be added to the field type when :default is not set and :enforce is not set; when set to false, prevents nil from being added in that case

How :default, :enforce and :null affect type and @enforce_keys

:default:enforce:nulltype@enforce_keys
set--t()excluded
unsettrue-t()included
unsetfalsetruet() | nilexcluded
unsetfalsefalset()excluded

parameter(name, opts \\ [])

(macro)

Defines a type parameter in a typed_structor/2.

Example

# A type parameter named int
parameter :int

field :number, int # not int()

plugin(plugin, opts \\ [])

(macro)

Registers a plugin for the currently defined struct.

Example

typed_structor do
  plugin MyPlugin

  field :string, String.t()
end

For more information on how to define your own plugins, please see TypedStructor.Plugin. To use a third-party plugin, please refer directly to its documentation.

typed_structor(options \\ [], list)

(macro)

Defines a struct with type information.

Inside a typed_structor block, you can define fields with the field/3 macro.

Options

  • :module - if provided, a new submodule will be created with the struct.
  • :enforce - if true, the struct will enforce the keys, see field/3 options for more information.
  • :null - if true (default), fields without a default value and not enforced will have nil added to their type. If false, prevents nil from being added.
  • :definer - the definer module to use to define the struct, record or exception. Defaults to :defstruct. It also accepts a macro that receives the definition struct and returns the AST. See definer section below.
  • :type_kind - the kind of type to use for the struct. Defaults to type, can be opaque or typep.
  • :type_name - the name of the type to use for the struct. Defaults to t.

Definer

The available definers are:

  • :defstruct, which defines a struct and a type for a given definition
  • :defexception, which defines an exception and a type for a given definition
  • :defrecord, which defines record macros and a type for a given definition
  • :defrecordp, which defines private record macros and a type for a given definition

:defstruct options

  • :define_struct - if false, the type will be defined, but the struct will not be defined. Defaults to true.

:defexception options

  • :define_struct - if false, the type will be defined, but the struct will not be defined. Defaults to true.

:defrecord and :defrecordp options

  • :record_name(required) - the name of the record, it must be provided.
  • :record_tag - if set, the record will be tagged with the given value. Defaults to nil.
  • :define_record - if false, the type will be defined, but the record will not be defined. Defaults to true.

custom definer

defmodule MyStruct do
  use TypedStructor

  typed_structor definer: MyDefiner do

    field :name, String.t()
    field :age, integer()
  end
end

Examples

defmodule MyStruct do
  use TypedStructor

  typed_structor do
    field :name, String.t()
    field :age, integer()
  end
end

Creates the struct in a submodule instead:

defmodule MyStruct do
  use TypedStructor

  typed_structor module: Struct do
    field :name, String.t()
    field :age, integer()
  end
end

To add a @typedoc to the struct type and @moduledoc to the submodule, just add the module attribute in the typed_structor block:

defmodule MyStruct do
  use TypedStructor

  typed_structor module: Struct do
    @typedoc "A typed struct"
    @moduledoc "A submodule"

    field :name, String.t()
    field :age, integer()
  end
end