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

@ethangunter/reshape

v0.1.1

Published

Wizardry for keeping data typesafe from definition to consumption

Readme

Reshape

npm version license TypeScript

A tiny, zero-dependency TypeScript utility for building type-safe object derivations from a single source of truth.

Why Reshape?

Your database schema, API response type, or any other canonical data structure should be the one true definition for your entire codebase. When it changes, everything downstream should change with it, automatically, with full type safety, and zero manual busywork.

Reshape gives you a fluent, chainable builder to derive new shapes from any TypeScript object. Omit sensitive fields, rename keys for a public API, recast values to different types, all while keeping TypeScript's type system perfectly in sync at every step.

Installation

npm install @ethangunter/reshape
pnpm add @ethangunter/reshape
yarn add @ethangunter/reshape

Requirements: TypeScript 5.0+, ESM project ("type": "module" or a bundler that handles ESM).

Use Case Example

You've got a user defined like so

type User = {
  _id: string;            // DB-bound naming
  _creationTime: number;  // DB-bound naming
  authId: string;         // Canonical id - frontend doesn't need to know it's auth-related
  name: string;
  email: string;          // Potentially sensitive in public user-searches
  passwordHash: string;   // DON'T SEND OUT OF DB
};

You want a clean, public-facing shape with no sensitive data, friendlier key names, and proper types. With Reshape:

export const toPublicUser = (user: User) =>
  reshape(user)
    // Strip sensitive internal fields
    .omit("_id", "passwordHash", "internalNotes")

    // Expose stable, public-friendly names instead of internal conventions
    .rename({ authId: "id", _creationTime: "createdAt" })

    // Convert values into the types consumers actually want
    .retype({ createdAt: t => new Date(t) })

    // Add any fields you want
    .extend({ source: "api" as const })
    .done();

And you get a runtime AND compile-time safe object out, no manual type definition required:

ReturnType<typeof toPublicUser> = {
  id: string;       // No _id, no authId, no mental overhead
  createdAt: Date;  // _creationTime is now an object we can work with
  name: string;
  email: string;
  source: "api";
}

No private fields compromising user privacy, and the compiler enforces it automatically! Change a field in User and every derived type and consumer updates with it.

API Reference

All methods return a new builder. The original object is never mutated. Call .done() to get the final typed object.

| Method | Description | | ------------------ | ------------------------------------------------------------------------ | | .omit(...keys) | Remove one or more keys | | .pick(...keys) | Keep only the specified keys | | .rename(mapping) | Rename keys via { oldKey: "newKey" } | | .retype(mapping) | Transform values via { key: (val) => newVal }, return type is inferred | | .extend(fields) | Merge in additional fields | | .done() | Finalize and return the object with its inferred type |

Exported types

import type { reshape, RenameKeys, Retype } from "@ethangunter/reshape";

| Type | Description | | ------------------------ | --------------------------------------------- | | Rename<Type, Mapping> | Utility type: rename keys on a type | | Retype<Type, Mapping> | Utility type: replace value types on a type |

Limitations

  • Transforms apply to top-level fields only. Nested transformation is not yet supported (coming soon).
  • retype transforms are applied at runtime. The inferred type reflects your function's return type, so make sure they match.

Contributing

PRs are welcome! For significant changes, please open an issue first to discuss what you'd like to change. Bug reports and feature requests can be filed via GitHub Issues.

License

MIT © 2026 Ethan Gunter