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

@toomuchdesign/json-schema-fns

v1.0.0

Published

Immutable, type-safe utilities for transforming and composing JSON Schemas.

Readme

@toomuchdesign/json-schema-fns

Build Status Npm version Coveralls

@toomuchdesign/json-schema-fns is a type-safe immutable utility library for transforming JSON Schemas.

It ensures that schema transformations not only update the runtime schema correctly but also preserve accurate TypeScript type inference. This makes it especially useful when paired with tools like json-schema-to-ts.

import { omitProps } from '@toomuchdesign/json-schema-fns';
import type { FromSchema } from 'json-schema-to-ts';

const userSchema = {
  type: 'object',
  properties: {
    id: { type: 'string' },
    password: { type: 'string' },
  },
  required: ['id', 'password'],
} as const;

const publicUserSchema = omitProps(userSchema, ['password']);
type PublicUser = FromSchema<typeof publicUserSchema>;
// { id: string }

Why?

Manipulating JSON Schemas directly can be verbose and error-prone.

This library provides small, focused utilities that keep runtime schemas and TypeScript types in sync — especially when paired with json-schema-to-ts.

Installation

npm install @toomuchdesign/json-schema-fns

API

Try it live ⚡ — every example below runs in the playground; open the file matching the function name.

All transformations preserve every keyword they don't explicitly touch. Input metadata like title, description, default, examples, $id, $defs, and any other keyword the library does not transform rides through to the output unchanged. The Touches column below lists the only keywords each function modifies.

| Function | Description | Touches | | --------------------------------------- | ---------------------------------------------------------------------------- | ----------------------------------------------- | | omitProps | Omit specific properties from an object JSON schema | properties, required | | omitPropsDeep | Omit specific nested properties using dot-notation paths | properties, required | | pickProps | Pick only specific properties from an object JSON schema | properties, required | | pickPropsDeep | Pick specific nested properties using dot-notation paths | properties, required | | mergeProps | Merge two object JSON schemas' properties and patternProperties into one | properties, patternProperties, required | | renameProps | Rename specific properties via an { oldKey: newKey } map | properties, required | | renamePropsDeep | Rename specific nested properties using dot-notation paths | properties, required | | requireProps | Mark specific properties as required (all if none provided) | required | | optionalProps | Make specific properties optional (all if none provided) | required | | sealSchemaDeep | Recursively set additionalProperties: false on all object schemas | additionalProperties | | unsealSchemaDeep | Recursively remove additionalProperties and unevaluatedProperties | additionalProperties, unevaluatedProperties |

omitProps

Omit specific properties from an object JSON schema.

import { omitProps } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  properties: {
    a: { type: 'string' },
    b: { type: 'number' },
  },
  required: ['a', 'b'],
} as const;

const result = omitProps(schema, ['b']);

omitPropsDeep

Omit specific nested properties from an object JSON schema using dot-notation paths. Paths sharing a common prefix are merged; a bare key drops the whole sub-schema, a dotted path drills in and drops only the leaf. When both forms target the same key, the bare-key drop wins.

import { omitPropsDeep } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  required: ['user', 'meta'],
  properties: {
    user: {
      type: 'object',
      required: ['id', 'password'],
      properties: {
        id: { type: 'string' },
        password: { type: 'string' },
      },
    },
    meta: { type: 'string' },
  },
} as const;

const result = omitPropsDeep(schema, ['user.password', 'meta']);

pickProps

Pick only specific properties from an object JSON schema.

import { pickProps } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  properties: {
    a: { type: 'string' },
    b: { type: 'number' },
  },
  required: ['a', 'b'],
} as const;

const result = pickProps(schema, ['b']);

pickPropsDeep

Pick specific nested properties from an object JSON schema using dot-notation paths. Paths sharing a common prefix are merged; a bare key (without a sub-path) keeps the whole sub-schema unchanged.

import { pickPropsDeep } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  required: ['user', 'meta'],
  properties: {
    user: {
      type: 'object',
      required: ['id', 'password'],
      properties: {
        id: { type: 'string' },
        password: { type: 'string' },
      },
    },
    meta: { type: 'string' },
  },
} as const;

const result = pickPropsDeep(schema, ['user.id', 'meta']);

mergeProps

Merge two object JSON schemas properties and patternProperties props into one. If the same property key exists in both schemas, the property from schema2 takes precedence. Top-level metadata (title, description, $id, etc.) follows the same rule — values from schema2 overwrite schema1 via spread. Combinators (allOf / anyOf / oneOf / not) are not merged; see docs/combinators.md.

import { mergeProps } from '@toomuchdesign/json-schema-fns';

const schema1 = {
  type: 'object',
  properties: {
    a: { type: 'string' },
  },
  required: ['a'],
} as const;

const schema2 = {
  type: 'object',
  properties: {
    b: { type: 'number' },
  },
  required: ['b'],
} as const;

const result = mergeProps(schema1, schema2);

renameProps

Rename specific properties in an object JSON schema via an { oldKey: newKey } map. Source keys must exist in schema.properties (compile error on unknown keys); target keys are arbitrary strings. Position in required is preserved. Shallow only.

import { renameProps } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  properties: {
    id: { type: 'string' },
    email: { type: 'string' },
  },
  required: ['id', 'email'],
} as const;

const result = renameProps(schema, { id: 'userId', email: 'emailAddress' });

renamePropsDeep

Rename specific nested properties in an object JSON schema using dot-notation paths. Source paths must resolve to existing properties (compile error on unknown paths); target names are arbitrary strings — renames don't move properties between levels. Bare and dotted entries can coexist: { user: 'account', 'user.id': 'userId' } renames user at the top level and id within it. Position in each level's required is preserved.

import { renamePropsDeep } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  required: ['user', 'meta'],
  properties: {
    user: {
      type: 'object',
      required: ['id', 'email'],
      properties: {
        id: { type: 'string' },
        email: { type: 'string' },
      },
    },
    meta: { type: 'string' },
  },
} as const;

const result = renamePropsDeep(schema, {
  'user.id': 'userId',
  meta: 'metadata',
});

requireProps

Mark specific properties in a object JSON schema as required. If no keys provided, all properties become required.

import { requireProps } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  properties: {
    a: { type: 'string' },
    b: { type: 'string' },
    c: { type: 'string' },
  },
  required: ['b'],
} as const;

const result = requireProps(schema, ['a', 'c']);

optionalProps

Make specific properties of a object JSON schema optional. If no keys provided, all properties become optional.

import { optionalProps } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  properties: {
    a: { type: 'string' },
    b: { type: 'string' },
    c: { type: 'string' },
  },
  required: ['a', 'b', 'c'],
} as const;

const result = optionalProps(schema, ['b', 'c']);

sealSchemaDeep

Recursively set additionalProperties: false on all object JSON schema schemas.

It does not modify JSON Schema combinators such as allOf, anyOf, oneOf, or not. This ensures that the logical combination of schemas remains intact and that the semantics of the schema are not altered in any way.

import { sealSchemaDeep } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  required: ['name'],
  properties: {
    name: { type: 'string' },
    address: {
      type: 'object',
      properties: {
        street: { type: 'string' },
      },
    },
  },
} as const;

const result = sealSchemaDeep(schema);

unsealSchemaDeep

Recursively remove additionalProperties and unevaluatedProperties keywords from all object JSON schema schemas.

It does not modify JSON Schema combinators such as allOf, anyOf, oneOf, or not. This ensures that the logical combination of schemas remains intact and that the semantics of the schema are not altered in any way.

import { unsealSchemaDeep } from '@toomuchdesign/json-schema-fns';

const schema = {
  type: 'object',
  additionalProperties: false,
  required: ['name'],
  properties: {
    name: { type: 'string' },
    address: {
      type: 'object',
      additionalProperties: false,
      properties: {
        street: { type: 'string' },
      },
    },
  },
} as const;

const result = unsealSchemaDeep(schema);

Composition & pipe-friendly API

In addition to the standard functional API, json-schema-fns also offers a composition-friendly counterpart that enables schema transformations through a pipeable interface. Live demo ⚡

Pipelines of at least 9 transformations are verified across all four endorsed pipe libraries (limited by pipe-ts's typed-overload cap of 9); remeda, effect, and ts-functional-pipe support deeper pipelines. See test/composition-pipe-depth-ceiling.test.ts for per-library ceilings.

Note: piping could lead TypeScript to hit its internal recursion limits producing the following error: TS2589: Type instantiation is excessively deep and possibly infinite

Note: the library does not include its own pipe utility. You are free to use any composition library you prefer. See composition tests for integration with each library.

import {
  pipeMergeProps,
  pipeOmitProps,
  pipeRequireProps,
  pipeSealSchemaDeep,
} from '@toomuchdesign/json-schema-fns';
import { pipeWith } from 'pipe-ts';

const schema = {
  type: 'object',
  properties: {
    a: { type: 'string' },
    b: { type: 'string' },
  },
  required: ['a'],
} as const;

const result = pipeWith(
  schema,
  pipeMergeProps({
    type: 'object',
    properties: {
      c: { type: 'string' },
    },
  }),
  pipeOmitProps(['a']),
  pipeRequireProps(['b']),
  pipeSealSchemaDeep(),
);

Supported JSON Schema dialect

The library targets JSON Schema Draft-07 (2018). Every transformation acts on a small known set of Draft-07 keywords (type, properties, patternProperties, required, additionalProperties, the combinators allOf / anyOf / oneOf / not, and the conditional applicators if / then / else).

Forward-compatibility is a design property. Schemas that use newer keywords from Draft 2019-09 or Draft 2020-12 — for example $defs, prefixItems, dependentRequired, propertyNames, $dynamicRef — pass through the library unchanged: every keyword the library does not explicitly transform rides through via TypeScript's const generic + Omit-based merge. See docs/types.md for the mechanics.

Type compatibility with json-schema-to-ts

The library accepts a homegrown JSONSchemaObject input type (kept separate from json-schema-to-ts's JSONSchema for type-performance reasons). In practice the two are compatible: any as const schema literal that is valid under json-schema-to-ts's JSONSchema type and uses only the keywords listed above is accepted as input, and every output schema is consumable by FromSchema. This is what makes FromSchema<typeof transformed> work in the example at the top of this README without any adapter.

Related projects

  • https://github.com/codeperate/json-schema-builder
  • https://github.com/livelybone/union-tuple
  • https://github.com/ksxnodemodules/typescript-tuple

Contributing

Contributions are welcome — see CONTRIBUTING.md for the workflow, local checks, and versioning policy. Before opening a PR, please run:

npx changeset