npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

Iโ€™ve always been into building performant and accessible sites, but lately Iโ€™ve been taking it extremely seriously. So much so that Iโ€™ve been building a tool to help me optimize and monitor the sites that I build to make sure that Iโ€™m making an attempt to offer the best experience to those who visit them. If youโ€™re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, ๐Ÿ‘‹, Iโ€™m Ryan Hefnerย  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If youโ€™re interested in other things Iโ€™m working on, follow me on Twitter or check out the open source projects Iโ€™ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soonโ€“ish.

Open Software & Tools

This site wouldnโ€™t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you ๐Ÿ™

ยฉ 2026 โ€“ย Pkg Stats / Ryan Hefner

@traversable/typebox

v0.0.31

Published

<br> <h1 align="center">แฏ“๐˜๐—ฟ๐—ฎ๐˜ƒ๐—ฒ๐—ฟ๐˜€๐—ฎ๐—ฏ๐—น๐—ฒ/๐˜๐˜†๐—ฝ๐—ฒ๐—ฏ๐—ผ๐˜…</h1> <br>

Downloads

29

Readme

Requirements

@traversable/typebox has a peer dependency on TypeBox (v0.34).

Getting started

$ pnpm add @traversable/typebox @sinclair/typebox

Here's an example of importing the library:

import * as T from '@sinclair/typebox'
import { box } from '@traversable/typebox'

// or, if you prefer, you can use named imports:
import { deepClone, deepEqual } from '@traversable/typebox'

// see below for specific examples

Table of contents

Fuzz-tested, production ready

Advanced

Features

box.deepClone

box.deepClone lets users derive a specialized "deep copy" function that works with values that have been already validated.

Because the values have already been validated, clone times are significantly faster than alternatives like window.structuredClone and Lodash.cloneDeep.

Performance comparison

Here's a Bolt sandbox if you'd like to run the benchmarks yourself.

                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                           โ”‚         (avg)   โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Lodash.cloneDeep        โ”‚  31.32x faster  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  window.structuredClone  โ”‚  54.36x faster  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

This article goes into more detail about what makes box.deepClone so fast.

Example

import * as T from '@sinclair/typebox'
import { box } from '@traversable/typebox'

const Address = T.Object({
  street1: T.String(),
  street2: T.Optional(T.String()),
  city: T.String(),
})

const deepClone = box.deepClone(Address)
const deepEqual = box.deepEqual(Address)

const sherlock = { street1: '221 Baker St', street2: '#B', city: 'London' }
const harry = { street1: '4 Privet Dr', city: 'Little Whinging' }

const sherlockCloned = deepClone(sherlock)
const harryCloned = deepClone(harry)

deepEqual(sherlockCloned, sherlock) // => true
deepEqual(harryCloned, harry)       // => true

sherlock === sherlockCloned         // => false
harry === harryCloned               // => false

See also

box.deepClone.writeable

box.deepClone.writeable lets users derive a specialized "deep clone" function that works with values that have been already validated.

Compared to box.deepClone, box.deepClone.writeable returns the clone function in stringified ("writeable") form.

Example

import { box } from '@traversable/typebox'

const deepClone = box.deepClone.writeable({
  type: 'object',
  required: ['street1', 'city'],
  properties: {
    street1: { type: 'string' },
    street2: { type: 'string' },
    city: { type: 'string' },
  }
}, { typeName: 'Address' })

console.log(deepClone) 
// =>
// type Address = { street1: string; street2?: string; city: string; }
// function deepClone(prev: Address): Address {
//   return {
//     street1: prev.street1,
//     ...prev.street2 !== undefined && { street2: prev.street2 },
//     city: prev.city
//   }
// }

See also

box.deepEqual

box.deepEqual lets users derive a specialized "deep equal" function that works with values that have been already validated.

Because the values have already been validated, comparison times are significantly faster than alternatives like NodeJS.isDeepStrictEqual and Lodash.isEqual.

Performance comparison

Here's a Bolt sandbox if you'd like to run the benchmarks yourself.

                             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                             โ”‚   Array (avg)  โ”‚  Object (avg)  โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  NodeJS.isDeepStrictEqual  โ”‚  40.3x faster  โ”‚  56.5x faster  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Lodash.isEqual            โ”‚  53.7x faster  โ”‚  60.1x faster  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

This article goes into more detail about what makes box.deepEqual so fast.

Notes

  • Best performance
  • Works in any environment that supports defining functions using the Function constructor, including (as of May 2025) Cloudflare workers ๐ŸŽ‰

Example

import { box } from '@traversable/typebox'

const deepEqual = box.deepEqual({
  type: 'object',
  required: ['street1', 'city'],
  properties: {
    street1: { type: 'string' },
    street2: { type: 'string' },
    city: { type: 'string' },
  }
})

deepEqual(
  { street1: '221B Baker St', city: 'London' },
  { street1: '221B Baker St', city: 'London' }
) // => true

deepEqual(
  { street1: '221B Baker St', city: 'London' },
  { street1: '4 Privet Dr', city: 'Little Whinging' }
) // => false

See also

box.deepEqual.writeable

box.deepEqual.writeable lets users derive a specialized "deep equal" function that works with values that have been already validated.

Compared to box.deepEqual, box.deepEqual.writeable returns the deep equal function in stringified ("writeable") form.

Notes

  • Useful when you're consuming a set of TypeBox schemas and writing all them to disc somewhere
  • Also useful for testing purposes or for troubleshooting, since it gives you a way to "see" exactly what the deepEqual functions are doing

Example

import { box } from '@traversable/typebox'

const deepEqual = box.deepEqual.writeable({
  type: 'object',
  required: ['street1', 'city'],
  properties: {
    street1: { type: 'string' },
    street2: { type: 'string' },
    city: { type: 'string' },
  }
}, { typeName: 'Address' })

console.log(deepEqual)
// =>
// type Address = { street1: string; street2?: string; city: string; }
// function deepEqual(x: Address, y: Address) {
//   if (x === y) return true;
//   if (x.street1 !== y.street1) return false;
//   if (x.street2 !== y.street2) return false;
//   if (x.city !== y.city) return false;
//   return true;
// }

See also

box.fold

[!NOTE] box.fold is an advanced API.

Use box.fold to define a recursive traversal of a TypeBox schema. Useful when building a schema rewriter.

What does it do?

Writing an arbitrary traversal with box.fold is:

  1. non-recursive
  2. 100% type-safe

The way it works is pretty simple: if you imagine all the places in the TypeBox schema that are recursive, those "holes" will be the type that you provide via type parameter.

Example

Let's write a function that takes an arbitrary TypeBox schema, and generates mock data that satisfies the schema (a.k.a. a "faker").

[!NOTE] You can play with this example on StackBlitz

import * as T from '@sinclair/typebox'
import { faker } from '@faker-js/faker'
import { F, tagged } from '@traversable/typebox'

type Fake = () => unknown

const fake = F.fold<Fake>((x) => {
  //                ๐™˜__๐™˜ this type parameter fills in the "holes" below
  switch (true) {
    case tagged('array')(x): return () => faker.helpers.multiple(
      () => x.items()
      //       ^? method items: Fake
      //                        ๐™˜__๐™˜
    )
    case tagged('never')(x): return () => void 0
    case tagged('unknown')(x): return () => void 0
    case tagged('any')(x): return () => void 0
    case tagged('void')(x): return () => void 0
    case tagged('null')(x): return () => null
    case tagged('undefined')(x): return () => undefined
    case tagged('symbol')(x): return () => Symbol()
    case tagged('boolean')(x): return () => faker.datatype.boolean()
    case tagged('integer')(x): return () => faker.number.int()
    case tagged('bigInt')(x): return () => faker.number.bigInt()
    case tagged('number')(x): return () => faker.number.float()
    case tagged('string')(x): return () => faker.lorem.words()
    case tagged('date')(x): return () => faker.date.recent()
    case tagged('literal')(x): return () => x.const
    case tagged('allOf')(x): return () => Object.assign({}, ...x.allOf)
    case tagged('anyOf')(x): return () => faker.helpers.arrayElement(x.anyOf.map((option) => option()))
    case tagged('optional')(x): return () => faker.helpers.arrayElement([x.schema, undefined])
    case tagged('tuple')(x): return () => x.items.map((item) => item())
    case tagged('record')(x): return () => Object.fromEntries(Object.entries(x.patternProperties).map(([k, v]) => [k, v()]))
    case tagged('object')(x): return () => Object.fromEntries(Object.entries(x.properties).map(([k, v]) => [k, v()]))
    default: { x satisfies never; throw Error('Unsupported schema') }
    //         ๐™˜_______________๐™˜
    //        exhaustiveness check works
  }
})

// Let's test it out:
const mock = fake(
  T.Object({
    abc: T.Array(T.String()), 
    def: T.Optional(
      T.Tuple([
        T.Number(), 
        T.Boolean()
      ])
    )
  })
)

console.log(mock())
// => {
//  abc: [
//     'annus iure consequatur',
//     'aer suus autem',
//     'delectus patrocinor deporto',
//     'benevolentia tonsor odit',
//     'stabilis dolor tres',
//     'mollitia quibusdam vociferor'
//   ],
//   def: [-882, false]
// }

Theory

box.fold is similar to, but more powerful than, the visitor pattern.

If you're curious about the theory behind it, its implementation was based on a 1991 paper called Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire.

See also

box.Functor

[!NOTE] box.Functor is an advanced API.

box.Functor is the primary abstraction that powers @traversable/typebox.

box.Functor is a powertool. Most of @traversable/typebox uses box.Functor under the hood.

Compared to the rest of the library, it's fairly "low-level", so unless you're doing something pretty advanced you probably won't need to use it directly.

See also