Standard library dictionaries
npm install @rcompat/dictDictionaries for JavaScript runtimes.
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.
``bash`
npm install @rcompat/dict
`bash`
pnpm add @rcompat/dict
`bash`
yarn add @rcompat/dict
`bash`
bun add @rcompat/dict
Checks if an object has no keys.
`js
import dict from "@rcompat/dict";
dict.empty({}); // true
dict.empty({ a: 1 }); // false
dict.empty({ a: undefined }); // false (key exists)
`
Chainable wrapper around Object.entries with filter, map, and transform
methods.
`js
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);
}
`
Creates a new object excluding specified keys.
`js
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" }
`
Gets a nested value using dot notation.
`js
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
`
Creates a nested object from a dot-notation path.
`js
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" } } }
`
Deep merges objects recursively. Values from the second object override the first.
`js
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 } }
`
Type guard that checks if a value is a non-null object.
`js
import dict from "@rcompat/dict";
dict.proper({}); // true
dict.proper([]); // true
dict.proper(null); // false
dict.proper(undefined); // false
dict.proper("string"); // false
`
Creates objects with null prototype (no inherited properties like toString).
`js
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
`
Converts an object to a URL query string.
`js
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"
`
`ts`
declare function empty(object: object): boolean;
Returns true if the object has no own keys.
`ts
declare function entries
interface Entries
filter(predicate: (entry: [K, V]) => boolean): Entries
map(mapper: (entry: [K, V]) => [K, U]): Entries
keymap(mapper: (entry: [K, V]) => K): Entries
valmap(mapper: (entry: [K, V]) => U): Entries
get(): dict
[Symbol.iterator](): IterableIterator<[K, V]>;
}
`
`ts`
declare function exclude
object: T,
keys: readonly K[]
): Omit
`ts`
declare function get
object: T,
path: P
): unknown;
` (ts`
declare function inflate
path: P,
initial?: T,
separator?: string
): object;
`ts`
declare function override
base: T,
over: U
): T & U;
`ts`
declare function proper(value: unknown): value is NonNullable
`ts`
declare function nullproto
init?: T,
options?: { frozen?: boolean }
): T;
`ts`
declare function toQueryString(dict: dict
`js
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();
}
`
`js
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 } }
`
`js
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"
`
`js
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
``
| Runtime | Supported |
|---------|-----------|
| Node.js | ✓ |
| Deno | ✓ |
| Bun | ✓ |
No configuration required — just import and use.
MIT
See CONTRIBUTING.md in the repository root.