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

@yopadd/copy

v1.0.0

Published

A type-safe immutable object manipulation library with fluent API

Readme

Copy

A type-safe immutable object manipulation library with fluent API. Create, transform, and collect objects with full type inference.

Installation

npm install @yopadd/copy

Features

  • Immutable operations: All transformations create new objects, preserving the original
  • Type-safe: Full TypeScript support with generic types that flow through all operations
  • Fluent API: Chainable methods for clean, readable code
  • Deep cloning: Uses structuredClone for deep copying of nested objects
  • Zero dependencies: Lightweight with no external dependencies
  • Performance mode: Optimized for temporary objects with fromMutable()

Usage

Basic Usage

import { Copy } from "@yopadd/copy";

// Create a copy from an object
const original = { name: "Alice", age: 30, email: "[email protected]" };
const copy = Copy.from(original);

// Get the cloned object
const result = copy.get();
// => { name: "Alice", age: 30, email: "[email protected]" }

Omit Properties

Remove specified properties from the copy:

const result = Copy.from({ a: 1, b: 2, c: 3 }).omit(["a", "c"]).get();
// => { b: 2 }

Keep Properties

Keep only specified properties:

const result = Copy.from({ a: 1, b: 2, c: 3 }).keep(["a", "c"]).get();
// => { a: 1, c: 3 }

Add Properties

Add new properties to the copy:

const result = Copy.from({ a: 1 }).add("b", 2).get();
// => { a: 1, b: 2 }

Add with Nullish Handling

Skip adding null or undefined values:

const copy = Copy.from({ a: 1 });
const result = copy
  .add("b", null, { ignoreNullish: true })
  .add("c", null)
  .add("e", undefined, { ignoreNullish: true })
  .add("f", undefined)
  .get();
// => { a: 1, c: null, f: undefined }  (b and e are not added)

Map Properties

Transform property values:

const result = Copy.from({ a: 1, b: 2 })
  .map("a", (x) => x * 10)
  .get();
// => { a: 10, b: 2 }

Collect to Class

Collect the final object into a class instance:

class User {
  constructor(data: { name: string; age: number }) {
    this.name = data.name;
    this.age = data.age;
  }
}

const user = Copy.from({ name: "Alice", age: 30 }).collectTo(User);
// => User { name: "Alice", age: 30 }

Chaining Operations

All methods are chainable for fluent transformations:

const result = Copy.from({ a: 1, b: 2, c: 3, d: 4 })
  .omit(["b"])
  .add("e", 5)
  .map("a", (x) => x + 10)
  .keep(["a", "c", "e"])
  .get();
// => { a: 11, c: 3, e: 5 }

Performance Mode: fromMutable()

For temporary/disposable objects where you don't need to preserve the input:

// HTTP response that won't be reused
const response = await fetchUser();

// No initial clone, transformations mutate the response directly
const user = Copy.fromMutable(response)
  .keep(["id", "name", "email"])
  .add("createdAt", new Date().toISOString())
  .collectTo(User);

// response is mutated, but we don't care since it's temporary

⚠️ WARNING: When using fromMutable():

  • The input object is NOT cloned initially
  • All transformation methods will mutate the input object
  • Use this only when the input is temporary and won't be reused
  • For safe usage, always use Copy.from()

API Reference

Copy.from<T>(struct: T): Copy<T>

Static method to create a new Copy instance from an object. Creates a deep clone immediately. Immutability is guaranteed.

Copy.fromMutable<T>(struct: T): Copy<T>

Static method to create a Copy instance without initial cloning. Optimized for temporary/disposable objects. The input will be mutated by transformation methods.

copy.omit<P>(props: P[]): Copy<T>

Returns a new Copy with the specified properties removed.

copy.keep<P>(props: P[]): Copy<T>

Returns a new Copy with only the specified properties.

copy.add<P, V>(prop: P, value: V, opts?: { ignoreNullish: boolean }): Copy<T>

Returns a new Copy with the specified property added.

  • If ignoreNullish is true, null and undefined values are not added

copy.map<P, V>(prop: P, mapper: (value: T[P]) => V): Copy<T>

Returns a new Copy with the specified property transformed.

copy.collectTo<C>(constructor: { new (args: T): C }): C

Collects the current state into a class instance.

copy.get(): T

Returns the final cloned object.

Type Safety

The library provides strong TypeScript typing:

  • Generic T type flows through all operations
  • omit() and keep() narrow the type to exclude/include only specified properties
  • add() extends the type with the new property
  • map() updates the type of the transformed property
  • All methods preserve type safety while allowing flexible transformations

Examples

Data Transformation Pipeline

interface UserData {
  id: number;
  name: string;
  email: string;
  password: string;
  createdAt: string;
}

function sanitizeUser(user: UserData) {
  return Copy.from(user).omit(["password"]).add("sanitized", true).get();
}

const user = {
  id: 1,
  name: "Alice",
  email: "[email protected]",
  password: "secret",
  createdAt: "2024-01-01",
};

const safeUser = sanitizeUser(user);
// => { id: 1, name: "Alice", email: "[email protected]", createdAt: "2024-01-01", sanitized: true }

Handling HTTP Response

import { Copy } from "@yopadd/copy";

interface ApiResponse {
  data: any;
  status: number;
  headers: Record<string, string>;
}

async function getUser() {
  const response = await fetch("/api/user");
  const data: ApiResponse = await response.json();
  
  // Optimized: no initial clone, we only need the data
  return Copy.fromMutable(data)
    .keep(["data"])
    .collectTo(User);
}

Partial Update with Type Safety

function updateUser<T extends { id: number }>(user: T, updates: Partial<T>) {
  return Copy.from(user)
    .add("updatedAt", new Date().toISOString())
    .map("id", (id) => id) // Just an example, id stays the same
    .get();
}

Code written by @yopadd. Documentation generated by Mistral Vibe.