TypeScript types reference#
The package is written in TypeScript and ships type declarations. The exported types are:
| Type | Purpose |
|---|---|
Validate |
signature of a custom validator: (val, update, state) => boolean, optionally carrying s/a/n metadata |
Update |
the object a validator fills in (see nodes) |
Context |
the validation context passed to a shape call |
Builder |
a node builder: (opts?, ...vals) => Node |
Node |
a compiled shape node |
State |
the traversal state passed to validators |
ShapeShape |
the return type of Shape(...)—the validator function plus its methods |
StandardSchemaV1 |
the Standard Schema interface every shape implements at runtime through shape['~standard']; the type Shape(...) returns does not declare it, so hand a shape over as shape as unknown as StandardSchemaV1 |
StandardSchemaV1Props, StandardSchemaV1Result, StandardSchemaV1Issue, StandardSchemaV1PathSegment, StandardSchemaV1Types |
the parts of that interface |
The options object (Shape(spec, options)) and the error description
(ErrDesc) have no exported names: use Parameters<typeof Shape>[1] and the
element type of Context['err'].
Result inference#
Shape(spec) infers the produced value's type from the spec, through every
builder. The spec is read as a const type, so tuples and literal values keep
their shape.
| In the spec | Inferred |
|---|---|
String, Number, Boolean, Date |
string, number, boolean, Date |
Array, Object, Function, Symbol |
any[], any, Function, symbol |
a literal (8080, 'x', true, a Date) |
its primitive (number, string, boolean, Date)—the literal is a default, not the only value |
null, /re/ |
null, string |
| a nested object | recursively inferred |
[X] |
X[]; [X, Y] a tuple [X, Y]; [] any[] |
'name: expr' key |
the property name—the expression text is not in the result |
a builder wrapping a spec (Min(1, Number), Required(...), Describe(...), Coerce(...), …) |
the spec's type |
Optional(X), Default(v, X) |
X—an absent value is filled from the default |
Skip(X), Ignore(X) |
X | undefined |
Nullable(X) |
X | null |
Integer—bare or called |
number |
Email, Url, Uuid, DateTime, Ip, Ipv4, Ipv6—bare or called |
string |
Never, Any, Func—bare or called |
never, any, Function |
Key(); Key(n); Key(n, sep); Key(fn) |
string; string[]; string; fn's return type |
Exact(a, b, …) |
the union of the literals, 'a' | 'b' |
One(A, B), Some(A, B), All(A, B) |
A | B—a branch with no spec of its own (Min(2)) is any, which absorbs the union |
Discriminated('kind', { dog: {…}, fish: {…} }) |
a union of the branches, each with kind: 'dog' or kind: 'fish' |
Child(X) |
{ [key: string]: X }; Rest(X) X[] |
Pick(names, X), Omit(names, X), Extend(extra, X), Partial(X) |
the reshaped object |
Transform(fn, X) |
fn's return type; Catch(fallback, X) X | typeof fallback |
Type(kind, …) |
the kind (Type(Number) and Type('Number') are number) |
a chain, Required(Number).Min(2) |
the same as the chain's first builder |
const shape = Shape({
name: Min(1, String), // string
port: 8080, // number
role: Exact('admin', 'user'), // 'admin' | 'user'
tags: Skip([String]), // string[] | undefined
'retries: Max(5)': 3, // retries: number
})
const out = shape(input) // { name: string, port: number, role: 'admin' | 'user', tags: string[] | undefined, retries: number }
An input typed any does not widen the result: shape(JSON.parse(text)) is
typed from the spec. An input typed as an object keeps its own extra properties
in the result, so an Open shape's unknowns survive at the type level.
shape.valid(value) is a type guard: in its true branch value is narrowed
to the input type intersected with the result.
The checks are in ts/test/types.test.ts, which the build compiles: a wrong
inference fails the build.
Importing#
import { Shape } from 'shape'
import type { Node, Context, Update, State } from 'shape'
Builders are named exports, and are also attached to Shape (so
const { Min } = require('shape') and Shape.Min are equivalent). G-prefixed
aliases exist for every builder to avoid clashing with local names.