# `Ash.Info.Manifest.Type`
[🔗](https://github.com/ash-project/ash/blob/v3.25.2/lib/ash/info/manifest/type.ex#L5)

Represents a resolved type in the API specification.

Named type modules (Ash.Type.Enum implementations, Ash.Type.NewType subtypes,
and embedded resources) are referenced inline with their full definitions
living in `%Ash.Info.Manifest{}.types`. This prevents circular references and
mirrors how non-embedded resources are referenced via `kind: :resource` with
definitions in `%Ash.Info.Manifest{}.resources`.

Embedded resources are *types*, not resources — they have no domain and no
callable surface. The standalone entry in `manifest.types` has
`kind: :embedded_resource` and `resource:` set to the full
`%Ash.Info.Manifest.Resource{}` definition.

Primitive types (string, integer, etc.) and anonymous containers (map/keyword/tuple
without a named module) are still resolved inline.

# `kind`

```elixir
@type kind() ::
  :string
  | :integer
  | :boolean
  | :float
  | :decimal
  | :uuid
  | :date
  | :datetime
  | :utc_datetime
  | :utc_datetime_usec
  | :naive_datetime
  | :time
  | :time_usec
  | :duration
  | :binary
  | :atom
  | :ci_string
  | :term
  | :enum
  | :union
  | :resource
  | :embedded_resource
  | :map
  | :struct
  | :array
  | :tuple
  | :keyword
  | :type_ref
  | :any
  | :unknown
```

# `t`

```elixir
@type t() :: %Ash.Info.Manifest.Type{
  allow_nil?: boolean() | nil,
  constraints: keyword() | nil,
  custom: map(),
  element_types: [%{name: atom(), type: t(), allow_nil?: boolean()}] | nil,
  fields: [%{name: atom(), type: t(), allow_nil?: boolean()}] | nil,
  instance_of: atom() | nil,
  item_type: t() | nil,
  kind: kind(),
  members: [%{name: atom(), type: t()}] | nil,
  module: atom() | nil,
  name: String.t(),
  resource: Ash.Info.Manifest.Resource.t() | nil,
  resource_module: atom() | nil,
  values: [atom()] | nil
}
```

# `effective_module`

```elixir
@spec effective_module(t()) :: atom() | nil
```

Returns the effective module for a type — `instance_of` if set, otherwise `module`.

For struct types wrapping a module (NewTypes, TypedStructs), `instance_of` points
to the original module. For other types, `module` is the Ash type module.

# `effective_resource`

```elixir
@spec effective_resource(t()) :: atom() | nil
```

Returns the effective resource module for a type.

For resource/embedded_resource types, returns `resource_module`.
Falls back to `effective_module/1`.

# `find_field`

```elixir
@spec find_field(t(), atom()) ::
  %{name: atom(), type: t(), allow_nil?: boolean()} | nil
```

Finds a sub-field by name from the type's field descriptors.

Returns the field map (`%{name, type, allow_nil?}`) or nil if not found.

# `find_field_type`

```elixir
@spec find_field_type(t(), atom()) :: t() | nil
```

Finds the type of a sub-field by name.

Returns the `%Ash.Info.Manifest.Type{}` of the field, or nil if not found.

# `find_member`

```elixir
@spec find_member(t(), atom()) :: map() | nil
```

Finds a union member by name from the type's members.

Returns the member map (`%{name, type, tag, tag_value}`) or nil.

# `get_fields`

```elixir
@spec get_fields(t()) :: [%{name: atom(), type: t(), allow_nil?: boolean()}]
```

Returns the list of field descriptors for a type.

Checks `.fields` first (for map/struct/keyword), then `.element_types` (for tuple).
Returns an empty list if neither is populated.

Each field is a map with `:name`, `:type` (`%Ash.Info.Manifest.Type{}`), and `:allow_nil?`.

# `has_fields?`

```elixir
@spec has_fields?(t()) :: boolean()
```

Returns true if the type has nested field descriptors (`.fields` or `.element_types`).

# `resource_kind?`

```elixir
@spec resource_kind?(t()) :: boolean()
```

Returns true if the type represents a resource (`:resource` or `:embedded_resource`).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
