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.