Browse API packages

API · v0.11.0

dict

Standard library dictionaries

Member signatures use schematic object.member(...) API notation. Exported type declarations are valid TypeScript.

Typed utilities for string-keyed dictionaries.

Inputs requiring plain objects are validated consistently with assert.dict(). Methods return new dictionaries unless their documentation states that the input itself is returned.

ts
import dict from "@rcompat/dict";

dict.empty#

Returns whether a dictionary has no own enumerable keys.

ts
dict.empty(dict: Dict): boolean;

Example

ts
dict.empty({}); // true
dict.empty({ ready: true }); // false

dict.entries#

Returns typed own enumerable key/value pairs.

ts
dict.entries<T extends Dict>(dict: T): [keyof T, T[keyof T]][];

Example

ts
dict.entries({ north: 1, south: 2 });
// [["north", 1], ["south", 2]]

dict.exclude#

Returns a copy without the selected keys.

ts
dict.exclude<T extends Dict, const E extends keyof T>(
  dict: T,
  excludes: readonly E[],
): Omit<T, E>;

Example

ts
dict.exclude({ name: "Ada", password: "secret" }, ["password"]);
// { name: "Ada" }

dict.filter#

Returns entries accepted by a key/value predicate.

ts
dict.filter<T extends Dict>(
  dict: T,
  predicate: (key: keyof T, value: T[keyof T]) => boolean,
): Partial<T>;

Example

ts
dict.filter({ a: 1, b: 2 }, (_key, value) => value > 1);
// { b: 2 }

dict.flatMap#

Maps entries and omits entries whose mapper returns an empty tuple.

ts
dict.flatMap<T extends Dict>(
  dict: T,
  mapper: (key: keyof T, value: T[keyof T]) => [string, unknown] | [],
): Dict;

Example

ts
dict.flatMap({ a: 1, b: 2 }, (key, value) =>
  value > 1 ? [key.toUpperCase(), value * 10] : []);
// { B: 20 }

dict.get#

Reads a value from a dot-separated nested path.

ts
dict.get<T extends Dict, P extends string>(
  dict: T,
  path: P,
): GetResultType<T, P>["result"];

Example

ts
dict.get({ server: { port: 8080 } }, "server.port"); // 8080

dict.has#

Checks for an own property and narrows the key to the dictionary keys.

ts
dict.has<D extends Dict>(dict: D, key: PropertyKey): key is keyof D;

Example

ts
dict.has({ name: "Ada" }, "name"); // true
dict.has({ name: "Ada" }, "age"); // false

dict.inflate#

Creates a nested dictionary from a path.

The by argument selects the path separator and defaults to ".".

ts
dict.inflate<P extends string>(path: P): Inflated<P, Dict, ".">;
dict.inflate<P extends string, T>(path: P, initial: T): Inflated<P, T, ".">;
dict.inflate<
  P extends string,
  T,
  B extends string>(path: P, initial: T, by: B): Inflated<P, T, B>;

Example

ts
dict.inflate("server.tls", { enabled: true });
// { server: { tls: { enabled: true } } }

dict.inflate("server/tls", { enabled: true }, "/");
// { server: { tls: { enabled: true } } }

dict.keys#

Returns typed own enumerable keys.

ts
dict.keys<T extends Dict>(dict: T): (keyof T)[];

Example

ts
dict.keys({ north: 1, south: 2 }); // ["north", "south"]

dict.new#

Creates a frozen, null-prototype copy of a plain object.

ts
dict.new<T extends object>(dict: T): T;

Example

ts
const config = dict.new({ mode: "production" });
Object.isFrozen(config); // true
Object.getPrototypeOf(config); // null

dict.map#

Maps values while preserving keys.

ts
dict.map<T extends Dict, U>(
  dict: T,
  mapper: (key: keyof T, value: T[keyof T]) => U,
): { [K in keyof T]: U };

Example

ts
dict.map({ a: 1, b: 2 }, (_key, value) => value * 10);
// { a: 10, b: 20 }

dict.mapKey#

Maps keys while preserving values.

ts
dict.mapKey<T extends Dict>(
  dict: T,
  mapper: (key: keyof T, value: T[keyof T]) => string,
): Dict<T[keyof T]>;

Example

ts
dict.mapKey({ north: 1, south: 2 }, key => key.toUpperCase());
// { NORTH: 1, SOUTH: 2 }

dict.override#

Recursively overlays one dictionary with another.

Values recognized by is.dict() are merged recursively; other overriding values replace their base values.

ts
dict.override<T extends Dict, U extends Dict>(base: T, over: U): T & U;

Example

ts
dict.override(
  { server: { host: "localhost", port: 3000 } },
  { server: { port: 8080 } },
);
// { server: { host: "localhost", port: 8080 } }

dict.toQueryString#

Joins string entries as unencoded key=value pairs.

ts
dict.toQueryString(dict: Dict<string>): string;

Example

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

dict.values#

Returns typed own enumerable values.

ts
dict.values<T extends Dict>(dict: T): T[keyof T][];

Example

ts
dict.values({ north: 1, south: 2 }); // [1, 2]

Supporting contracts#

GetResultType#

Resolves the value type at a dot-separated dictionary path.

Type parameters

  • T — Dictionary type to traverse.
  • P — Dot-separated path.
  • D — Internal recursion-depth counter.
ts
interface GetResultType<T, P, D extends number[] = []> {
  result: D["length"] extends 6
  ? unknown
  : P extends `${infer P1}.${infer Rest}`
  ? P1 extends keyof T
  ? GetResultType<Exclude<T[P1], undefined>, Rest, [...D, 0]>["result"]
  | (T[P1] & undefined)
  : undefined
  : P extends keyof T
  ? T[P]
  : undefined;
}

Inflated#

Builds a nested dictionary type from a path and separator.

Type parameters

  • P — Path to expand.
  • T — Leaf value type.
  • B — Path separator.
ts
type Inflated<P extends string, T, B extends string> =
  P extends `${infer P1}${B}${infer Rest}` ?
  { [K in P1]: Inflated<Rest, T, B> } :
  { [K in P]: T };