doc/option-types: Improve union type docs (#456505)

This commit is contained in:
Johannes Kirschbauer 2025-10-29 08:26:56 +00:00 committed by GitHub
commit 1e4d803890
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -316,22 +316,34 @@ A union of types is a type such that a value is valid when it is valid for at le
If some values are instances of more than one of the types, it is not possible to distinguish which type they are meant to be instances of. If that's needed, consider using a [sum type](#sec-option-types-sums).
<!-- SYNC WITH oneOf BELOW -->
`types.either` *`t1 t2`*
: Type *`t1`* or type *`t2`*, e.g. `with types; either int str`.
Multiple definitions cannot be merged.
::: {.warning}
`either` and `oneOf` eagerly decide the active type based on the passed types' shallow check method. For composite types like `attrsOf` and `submodule`, which both match all attribute set definitions, the first type argument will be chosen for the returned option value, and this therefore also decides how nested values are checked and merged. For example, `either (attrsOf int) (submodule {...})` will always use `attrsOf int` for any attribute set value, even if it was intended as a submodule. This behavior is a trade-off that keeps the implementation simple and the evaluation order predictable, avoiding unexpected strictness problems such as infinite recursions. When proper type discrimination is needed, consider using a [sum type](#sec-option-types-sums) like `attrTag` instead.
:::
<!-- SYNC WITH either ABOVE -->
`types.oneOf` \[ *`t1 t2`* ... \]
: Type *`t1`* or type *`t2`* and so forth, e.g.
`with types; oneOf [ int str bool ]`. Multiple definitions cannot be
merged.
::: {.warning}
`either` and `oneOf` eagerly decide the active type based on the passed types' shallow check method. For composite types like `attrsOf` and `submodule`, which both match all attribute set definitions, the first matching type in the list will be chosen for the returned option value, and this therefore also decides how nested values are checked and merged. For example, `oneOf [ (attrsOf int) (submodule {...}) ]` will always use `attrsOf int` for any attribute set value, even if it was intended as a submodule. This behavior is a trade-off that keeps the implementation simple and the evaluation order predictable, avoiding unexpected strictness problems such as infinite recursions. When proper type discrimination is needed, consider using a [sum type](#sec-option-types-sums) like `attrTag` instead.
:::
`types.nullOr` *`t`*
: `null` or type *`t`*. Multiple definitions are merged according to
type *`t`*.
This is mostly equivalent to `either (enum [ null ]) t`, but `nullOr` provides a `null` fallback for attribute values with `mkIf false` definitions in `lazyAttrsOf (nullOr t)`, whereas `either` would throw an error when the attribute is accessed.
## Sum types {#sec-option-types-sums}