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

@rcompat/dict

v0.3.0

Published

Standard library dictionaries

Readme

@rcompat/dict

Dictionaries for JavaScript runtimes.

What is @rcompat/dict?

A cross-runtime module providing utilities for working with dictionaries (plain objects). Includes chainable entry manipulation, deep merging, path-based access, and more. Works consistently across Node, Deno, and Bun.

Installation

npm install @rcompat/dict
pnpm add @rcompat/dict
yarn add @rcompat/dict
bun add @rcompat/dict

Usage

empty

Checks if an object has no keys.

import dict from "@rcompat/dict";

dict.empty({});               // true
dict.empty({ a: 1 });         // false
dict.empty({ a: undefined }); // false (key exists)

entries

Chainable wrapper around Object.entries with filter, map, and transform methods.

import entries from "@rcompat/dict/entries";

const obj = { a: 1, b: 2, c: 3 };

// filter entries
entries(obj)
  .filter(([key, value]) => value > 1)
  .get();  // { b: 2, c: 3 }

// map values
entries(obj)
  .valmap(([key, value]) => value * 2)
  .get();  // { a: 2, b: 4, c: 6 }

// map keys
entries(obj)
  .keymap(([key]) => key.toUpperCase())
  .get();  // { A: 1, B: 2, C: 3 }

// chain operations
entries(obj)
  .filter(([, v]) => v > 1)
  .valmap(([, v]) => v * 10)
  .get();  // { b: 20, c: 30 }

// iterate
for (const [key, value] of entries(obj)) {
  console.log(key, value);
}

exclude

Creates a new object excluding specified keys.

import dict from "@rcompat/dict";

const user = { id: 1, name: "Bob", password: "secret" };

dict.exclude(user, ["password"]);
// { id: 1, name: "Bob" }

dict.exclude(user, ["id", "password"]);
// { name: "Bob" }

get

Gets a nested value using dot notation.

import dict from "@rcompat/dict";

const data = {
  user: {
    profile: {
      name: "Bob",
    },
  },
};

dict.get(data, "user.profile.name");  // "Bob"
dict.get(data, "user.profile");       // { name: "Bob" }
dict.get(data, "user.missing");       // undefined

inflate

Creates a nested object from a dot-notation path.

import dict from "@rcompat/dict";

dict.inflate("a.b.c");
// { a: { b: { c: {} } } }

dict.inflate("a.b.c", "value");
// { a: { b: { c: "value" } } }

dict.inflate("a/b/c", "value", "/");
// { a: { b: { c: "value" } } }

override

Deep merges objects recursively. Values from the second object override the first.

import dict from "@rcompat/dict";

dict.override({ a: 1 }, { b: 2 });
// { a: 1, b: 2 }

dict.override({ a: 1 }, { a: 2 });
// { a: 2 }

// Deep merge
dict.override(
  { user: { name: "Bob", age: 30 } },
  { user: { age: 31 } }
);
// { user: { name: "Bob", age: 31 } }

proper

Type guard that checks if a value is a non-null object.

import dict from "@rcompat/dict";

dict.proper({});          // true
dict.proper([]);          // true
dict.proper(null);        // false
dict.proper(undefined);   // false
dict.proper("string");    // false

nullproto

Creates objects with null prototype (no inherited properties like toString).

import dict from "@rcompat/dict";

// Empty null-prototype object
const empty = dict.nullproto();
empty.toString;  // undefined (no inherited methods)

// With initial values
const obj = dict.nullproto({ a: 1, b: 2 });
obj.a;           // 1
obj.toString;    // undefined

// Frozen (immutable)
const frozen = dict.nullproto({ a: 1 }, { frozen: true });
frozen.a = 2;    // TypeError in strict mode

toQueryString

Converts an object to a URL query string.

import dict from "@rcompat/dict";

dict.toQueryString({ page: "1", sort: "name" });
// "page=1&sort=name"

dict.toQueryString({ q: "hello", limit: "10" });
// "q=hello&limit=10"

API Reference

empty(object)

declare function empty(object: object): boolean;

Returns true if the object has no own keys.

entries(dict)

declare function entries<K extends string, V>(dict: dict<K, V>): Entries<K, V>;

interface Entries<K, V> {
  filter(predicate: (entry: [K, V]) => boolean): Entries<K, V>;
  map<U>(mapper: (entry: [K, V]) => [K, U]): Entries<K, U>;
  keymap(mapper: (entry: [K, V]) => K): Entries<K, V>;
  valmap<U>(mapper: (entry: [K, V]) => U): Entries<K, U>;
  get(): dict<K, V>;
  [Symbol.iterator](): IterableIterator<[K, V]>;
}

exclude(object, keys)

declare function exclude<T extends object, K extends keyof T>(
  object: T,
  keys: readonly K[]
): Omit<T, K>;

get(object, path)

declare function get<T extends object, P extends string>(
  object: T,
  path: P
): unknown;

inflate(path, initial?, separator?)

declare function inflate<P extends string, T>(
  path: P,
  initial?: T,
  separator?: string
): object;

override(base, over)

declare function override<T extends object, U extends object>(
  base: T,
  over: U
): T & U;

proper(value)

declare function proper(value: unknown): value is NonNullable<object>;

nullproto(init?, options?)

declare function nullproto<T extends object>(
  init?: T,
  options?: { frozen?: boolean }
): T;

toQueryString(dict)

declare function toQueryString(dict: dict<string, string>): string;

Examples

Sanitize API response

import dict from "@rcompat/dict";

function sanitizeUser(user) {
  return dict.exclude(user, ["password", "ssn", "creditCard"]);
}

function transformResponse(data) {
  return dict.entries(data)
    .filter(([key]) => !key.startsWith("_"))
    .valmap(([, value]) => value ?? "N/A")
    .get();
}

Configuration with defaults

import dict from "@rcompat/dict";

const defaults = {
  host: "localhost",
  port: 3000,
  db: {
    host: "localhost",
    port: 5432,
  },
};

function createConfig(userConfig) {
  return dict.override(defaults, userConfig);
}

createConfig({ port: 8080, db: { port: 5433 } });
// { host: "localhost", port: 8080, db: { host: "localhost", port: 5433 } }

Build URL with query params

import dict from "@rcompat/dict";

function buildUrl(base, params) {
  const query = dict.toQueryString(params);
  return query ? `${base}?${query}` : base;
}

buildUrl("/api/users", { page: "1", limit: "10" });
// "/api/users?page=1&limit=10"

Safe configuration objects

import dict from "@rcompat/dict";

// Prevent prototype pollution
const config = dict.nullproto({
  apiKey: "secret",
  endpoint: "https://api.example.com",
}, { frozen: true });

// Safe from prototype attacks
config.__proto__;     // undefined
config.constructor;   // undefined

Cross-Runtime Compatibility

| Runtime | Supported | |---------|-----------| | Node.js | ✓ | | Deno | ✓ | | Bun | ✓ |

No configuration required — just import and use.

License

MIT

Contributing

See CONTRIBUTING.md in the repository root.