saleyn
TypedStruct 0.6.2: Added Ecto Integration, Default Plugins, and Enhanced Struct Features
I wanted to share some exciting updates to TypedStruct that have landed recently, bringing significant improvements to struct definition ergonomics, database integration, and runtime utilities.
What’s New
1. Validated Constructor Generation
Generate automatic constructors with validation for your structs. Enable with constructors: true:
defmodule User do
use TypedStruct
typedstruct constructors: true do
field :name, String.t(), enforce: true
field :age, integer()
end
end
# Generated constructors:
User.new(name: "Alice", age: 30) # Safe creation with validation
User.new!(name: "Alice") # Raises on invalid data
User.from_map(%{"name" => "Alice"}) # From map
User.from_keyword(name: "Alice") # From keyword list
# For typedrecord:
# user_new/1, user_new!/1, user_from_map/1, user_from_keyword/1
2. Reflection Helpers
Get runtime reflection information about your structs with reflection: true:
defmodule User do
use TypedStruct
typedstruct reflection: true do
field :id, integer(), enforce: true
field :name, String.t(), enforce: true
field :email, String.t()
field :active, boolean(), default: true
end
end
# Generated helpers:
User.__fields__() # [:id, :name, :email, :active]
User.__required__() # [:id, :name]
User.__defaults__() # %{email: nil, active: true}
User.__types__() # Internal type info for tooling
# For typedrecord named :user:
# user_fields/0, user_required/0, user_defaults/0, user_types/0
3. Dynamic Defaults with default_fn
Use dynamic defaults generated at construction time:
defmodule Token do
use TypedStruct
defmodule Defaults do
def token, do: :crypto.strong_rand_bytes(32) |> Base.encode16()
def timestamp, do: System.os_time(:second)
end
typedstruct do
field :value, binary(), default_fn: &Defaults.token/0
field :created_at, integer(), default_fn: &Defaults.timestamp/0
end
end
# Each new token gets a fresh random value and timestamp
4. Strict Mode
Enforce all fields to either be enforced or have defaults:
defmodule StrictUser do
use TypedStruct
typedstruct strict: true do
field :id, integer(), enforce: true
field :name, String.t(), enforce: true
field :active, boolean(), default: true
# field :email, String.t() # Error: must have enforce or default!
end
end
iex(2)> %StrictUser{}
** (ArgumentError) the following keys must also be given when building struct StrictUser: [:name, :id]
expanding struct: StrictUser.__struct__/1
5. Protocol Derivation Passthrough
Pass through derive options to defstruct:
defmodule User do
use TypedStruct
typedstruct derive: [Inspect, Poison.Encoder] do
field :id, integer()
field :name, String.t()
end
end
6. Default Plugins for Wrapper Macros
Specify default plugins when creating TypedStruct wrapper modules:
defmodule MyApp.Type do
defmacro __using__(_) do
quote do
use TypedStruct, plugins: [MyApp.TypedStruct.Plugin.Validators]
end
end
end
defmodule MyApp.User do
use MyApp.Type # Automatically gets Validators plugin
typedstruct do
field :name, String.t(), enforce: true
end
end
7. Ecto Schema Integration
Define Ecto schemas with automatic type inference in a single, unified syntax:
defmodule User do
use TypedStruct.Ecto
typedschema "users" do
field :email, :string, enforce: true
field :age, :integer
belongs_to :company, Company
has_many :posts, Post
timestamps()
end
end
The typedschema macro:
- Automatically infers Elixir types from Ecto field types (20+ type mappings)
- Generates both Ecto schema and TypedStruct with matching types
- Handles all association types:
belongs_to,has_many,has_one,many_to_many - Supports regular and polymorphic embeds
- Enables type overrides with
::syntax
8. Polymorphic Embed Support
When you have the polymorphic_embed library installed, TypedStruct.Ecto automatically generates proper union types:
defmodule Notification do
use TypedStruct.Ecto
typedschema "notifications" do
field :message, :string, enforce: true
polymorphic_embeds_one :channel,
types: [
email: EmailConfig,
sms: SMSConfig,
push: PushConfig
],
on_replace: :update
timestamps()
end
end
9. Field Documentation via @doc Attribute
Document fields using the @doc attribute directly in your struct:
typedstruct do
@doc "User's full name"
field :name, String.t()
@doc "Email address for notifications"
field :email, String.t(), enforce: true
end
Why This Matters
These features address common pain points in Elixir development:
- Less Boilerplate — Generate constructors and reflection helpers automatically
- Type Safety — Static types with runtime constructor validation
- Optional Database Integration — Keep schemas and types in sync with
TypedStruct.Ecto - Runtime Reflection — Inspect struct metadata programmatically
- Flexible Defaults — Support both static and dynamic default values
- Protocol Support — Derive protocols like
InspectandJason.Encoder
Feel free to open issues or discussions on the GitHub repository.
Trending in News & Updates
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #code-sync
- #discussion
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #ai
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #elixirconf-us
- #blog-post
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #elixirconf-eu
- #processes
- #security
- #api
- #forms
- #performance











Showing Posts 1 to 1- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
saleyn
Also added support for defining Erlang records with type information and their pretty-printing: