shape

How to rename properties and reuse shapes#

Goal: rename a property after validation, or define a shape once and reference it elsewhere (including recursively).

Rename a property#

Rename({ name }) validates the value and moves it to a new key.

TS

const { Shape, Rename } = require('shape')   // Number is the JS global
const shape = Shape({ id: Rename({ name: 'userId' }, Number) })

shape({ id: 7 })   // → { userId: 7 }

Go

s := shape.MustShape(map[string]any{
    "id": shape.Rename("userId", shape.Number),
})

Options (passed in the first argument object in TS; via RenameWith in Go):

Option Effect
keep keep the original key as well as the renamed one
claim list of alternate source keys to pull the value from if absent
Shape({ userId: Rename({ name: 'userId', claim: ['id', 'uid'] }, Number) })
// accepts { id: 7 } or { uid: 7 } → { userId: 7 }

Define and refer to a shape#

Define(name, shape) records a shape under a name during validation; Refer(name) substitutes it. This is the basis for recursive shapes.

TS

const { Shape, Define, Refer } = require('shape')

const tree = Shape(Define('node', {
  value: Number,
  children: [Refer('node')],   // each child is another node
}))

tree({ value: 1, children: [{ value: 2, children: [] }] })  // OK

Go

s := shape.MustShape(shape.Define("node", map[string]any{
    "value":    shape.Number,
    "children": []any{shape.Refer("node")},
}))

Fill from a reference even when absent#

By default Refer only substitutes when a value is present (this prevents infinite loops for self-referential shapes). To substitute even when the value is missing, enable fill:

TS

Shape({ copy: Refer({ name: 'shared', fill: true }) })

Go

shape.ReferWith("shared", shape.ReferOptions{Fill: true})

A Refer whose name no Define supplies does nothing: the value is validated by the Refer's own shape, if it has one. To make that a mistake rather than a no-op, ask for strict:

Shape({ copy: Refer({ name: 'shared', strict: true }) })
// Value "1" for property "copy" refers to "shared", which is not defined.
shape.ReferWith("shared", shape.ReferOptions{Strict: true})

Use fill only when the reference is not self-recursive, or you will create an infinite expansion.

See also#