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

improved-record

v1.0.1

Published

Lightweight wrapper around immutable.js Record to make it better for TypeScript usage.

Readme

Improved Immutable Record

Build Status

ImprovedRecord is a lightweight wrapper around the immutable.js Record type. This is intended only for use with TypeScript, as it takes advantage of the type system to ensure safety while allowing for more flexible use.

The primary benefit of ImprovedRecord is the ability to declare properties that do not have a default value. These properties are required to be set when creating a new record instance, and they cannot be deleted (only changed).

ImprovedRecord is inspired by Scala's case classes, which work in a very similar way.

Comparison with immutable.js Record

| | immutable.js Record | ImprovedRecord | | --------------------------------------------- | --------------------- | ----------------------------- | | Properties can be declared without defaults | ❌ | ✅ | | Properties can be deleted (reset to default) | ✅ | Only properties with defaults | | Shape easily defined by TypeScript interfaces | ✅ | ✅ | | 100% safe at runtime | ✅ | ❌ | | 100% safe at compile-time | ✅ | ✅ | | Completely immutable | ✅ | ✅ |

Getting Started

Installation

NPM

npm i improved-record

Yarn

yarn add improved-record

Usage

The API for ImprovedRecord is almost exactly the same as the API for the original Record.

Here are all the differences:

  • The shape interface type parameter is required (cannot be correctly inferred).
  • When creating factories, default values can only be specified for optional properties on the shape interface (properties defined like property?: Type).
  • When creating factories, all required properties must have their default set to the unique required symbol. This is required because of how immutable.js works behind the scenes.
  • undefined cannot be used as a default value or as a value for required types. Use null instead.
  • When creating record instances, all properties without default values (required properties in the shape interface) are required. Properties with default values can still be overridden.
  • When calling delete or remove on an instance, only properties with defaults (optional properties in the shape interface) may be deleted. Names of properties without defaults cannot be passed.
  • The clear method is not available (because there are no default values for some properties).
  • The deleteIn and removeIn methods are not available (because there is no way to safely type- check these methods and prevent required properties from being deleted).

That's it! Everything else is the same.

Example

Here's a full example with a sample Person record:

Defining a factory

import {ImprovedRecord, ImprovedRecordOf, required} from "improved-immutable-record";

// The props interface is required (cannot be correctly inferred from the default values):
interface PersonProps {
  // For required properties like this, no default value will be defined.
  username: string;
  // Properties marked optional will always have a default value defined.
  level?: "admin" | "user";
  // The `| undefined` here will have no effect as `undefined` is not a valid value.
  displayName: string | undefined;
  // For truly optional properties, `null` can be used as the default value. `undefined` cannot be
  // the default value.
  age?: number | null;
}

// Now create the record factory. Providing the props interface is required.
const Person = ImprovedRecord<PersonProps>({
  // Set required properties to the unique `required` symbol.
  username: required,
  // Any optional property *must* have a default value.
  level: "user",
  // Even though `displayName` has `| undefined`, it is still a required property (no `?:`).
  displayName: required,
  age: null
});

// Define the record instance type with the same name as the record factory (this is optional but
// makes it much easier to work with and helps to avoid accidentally using `PersonProps` instead of
// `Person`.
type Person = ImprovedRecordOf<PersonProps>;

export default Person;

Using the factory

import Person from "Person";

// Using the factory method:
const samplePerson = Person({
  // Required properties must be defined.
  username: "sample123",
  // `displayName` cannot be set to `undefined`
  displayName: "unknown"
  // `age` and `level` don't have to be set because they have defaults.
});

// `Person` is also a type due to declaration merging:
const doSomething = (person: Person): void => {
  /* ... */
};

doSomething(samplePerson);