Introspection
Types have an extremely powerful internal representation defined in @ark/schema
that is primarily exposed through the .internal
property on each Type.
Though APIs under .internal
are not officially frozen, they are stable enough that we want to start giving users more direct access to some of the introspection capabilities they provide.
Node kinds
All nodes have a kind
property indicating their purpose, structure and special properties.
Roots
The kind
at the root of a Type will always be one of the following root kind.
Bases
The simplest root nodes are defined by a single basis constraint.
Only a single basis can exist in an intersection. From widest to narrowest:
kind | description | example |
---|---|---|
domain | One of 5 non-enumerable type sets ( | { domain: "string" } |
proto | A constructor checked by | { proto: Date } |
unit | An exact value checked by | { unit: true } |
Composites
Root kinds are built from references to other nodes.
Will be normalized to appear in approximately the following hierarchical order:
kind | description | example |
---|---|---|
alias | Stores a cyclic reference to a node | { reference: "$name" } |
union | A set of allowed nodes | { branches: ["string", "Array"] } |
morph | One or more transformations applied to valid data | { in: "string", morphs: [(s) => s.trim()] } |
intersection | An intersection of constraints | { domain: "number", divisor: 5 } |
Constraints
Constraint nodes exist on an intersection
(or its structure
) and narrow the set of values allowed by its basis.
Refinements
Constraints that apply directly to the root of an intersection (includes the base structure
node but not its children).
kind | impliedBasis | description | example |
---|---|---|---|
divisor | number | Multiple of the specified integer | { rule: 2 } |
pattern | string | Matched by a regex | { rule: "^[a-z]+$" } |
min | number | Numeric minimum (inclusive by default) | { rule: 0, exclusive: true } |
max | number | Numeric maximum (inclusive by default) | { rule: 100 } |
minLength | string | Array | Inclusive minimum length | { rule: 1 } |
maxLength | string | Array | Inclusive maximum length | { rule: 255 } |
exactLength | string | Array | Exact length | { rule: 10 } |
after | Date | Minimum Date (inclusive by default) | { rule: new Date("2000-01-01") } |
before | Date | Maximum Date (inclusive by default) | { rule: new Date() } |
predicate | unknown | Custom narrow function | { predicate: (n) => n % 2 === 1 } |
Structural
These constraints refine a structure
node, defining the shape of properties and/or array elements.
kind | description | example |
---|---|---|
sequence | Array/tuple shape | { prefix: ["string"], variadic: "number" } |
required | Required object property | { key: "id", value: "number" } |
optional | Optional object property | { key: "name", value: "string" } |
index | Properties allowed by signature must conform to value | { signature: "string", value: "boolean" } |
More details on the type system to come!
select
select is not fully stable!
select
relies on the internal representation defined in @ark/schema
, which although relatively mature, is not guaranteed semver-stable.
select
is the top-level first method we're introducing for interacting with a Type based on its internal representation.
It can be used to filter a Type's references:
This can be used directly or in combination with the configure
API for fine-grained control over which nodes to modify.