This guide is a compact, self-contained reference for assistants (and humans) integrating @karmaniverous/entity-tools into TypeScript projects. It focuses on the library’s contracts, invariants, and minimum working patterns.
sort(items, sortOrder) — progressive sort over entity properties.updateItem(item, update) — shallow updates with null/undefined conventions.isNil(value) / Nil — nil guard + alias (null | undefined).conditionalize(fn, condition?) — gate function execution on a truthy condition.defineTranscodes(spec) — inference-first transcoder registry builder with compile-time encode/decode agreement.defaultTranscodes / DefaultTranscodeRegistry — ready-made registry for common value types.encodePairs, decodePairs.hashString, enumerateShardSuffixes, shardSuffixFromHash.npm i @karmaniverous/entity-tools
sortOrder; later keys break ties from earlier keys.number, string, bigint: compared naturally.null/undefined: treated as equivalent and sort before any defined value.Minimal example:
import { sort, type SortOrder } from '@karmaniverous/entity-tools';
type User = {
id: number;
name: string;
optional?: string | null;
};
const users: User[] = [
{ id: 2, name: 'Adam', optional: 'foo' },
{ id: 4, name: 'Adam' },
{ id: 1, name: 'Charlie', optional: null },
];
const order: SortOrder<User> = [
{ property: 'name' },
{ property: 'id', desc: true },
];
const out = sort(users, order);
Use defineSortOrder<E>() when you want TypeScript to preserve property-name literals (and error on invalid property names) at the call site:
import { defineSortOrder, type Entity } from '@karmaniverous/entity-tools';
type E = Entity & { x: number; y: string };
const so = defineSortOrder<E>([{ property: 'x' }]);
// @ts-expect-error
defineSortOrder<E>([{ property: 'z' }]);
Update conventions:
undefined in update is ignored.null in update is assigned during merge, then stripped from the final result (along with undefined).null/undefined properties (they are removed).import { updateItem } from '@karmaniverous/entity-tools';
const original = { id: 1, name: 'Alice', note: undefined as string | undefined };
const patch = { name: 'Alicia', note: null, extra: undefined as string | undefined };
const updated = updateItem(original, patch);
// => { id: 1, name: 'Alicia' }
{ encode: (value: V) => string; decode: (value: string) => V }.{ int: number; bool: boolean }.{ encode, decode } functions.
defineTranscodes is an identity function at runtime, but its type signature enforces:
encode(value) => string,decode(string) => V,Example (inference-first):
import { defineTranscodes } from '@karmaniverous/entity-tools';
import type {
TranscodeRegistryFrom,
TranscodedType,
TranscodeName,
} from '@karmaniverous/entity-tools';
const spec = {
int: {
encode: (v: number) => v.toString(),
decode: (s: string) => Number(s),
},
boolean: {
encode: (v: boolean) => (v ? 't' : 'f'),
decode: (s: string) => s === 't',
},
} as const;
const transcodes = defineTranscodes(spec);
type TR = TranscodeRegistryFrom<typeof spec>;
type Names = TranscodeName<TR>; // 'int' | 'boolean'
type TInt = TranscodedType<TR, 'int'>; // number
If encode/decode disagree, TypeScript will error at the call site (this is intentionally strict).
defaultTranscodes implements a standard set of transcoders:
boolean: "t" / "f"string: identitynumber: decimal stringfix6: fixed width with 6 decimals, signed, lexicographically sortableint: fixed width signed integer (16 digits), lexicographically sortablebigint: decimal stringbigint20: fixed width signed BigInt up to 20 digits, lexicographically sortabletimestamp: 13-digit unix millis (0..9999999999999), zero-paddedimport { defaultTranscodes } from '@karmaniverous/entity-tools';
const s = defaultTranscodes.int.encode(-123); // "n0000000000000123"
const n = defaultTranscodes.int.decode(s); // -123
These helpers do not escape delimiters; callers must choose delimiters that do not appear in keys/values if round-trip safety is required.
import { encodePairs, decodePairs } from '@karmaniverous/entity-tools';
const pairs: Array<[string, string]> = [
['k1', 'v1'],
['k2', ''],
];
const enc = encodePairs(pairs); // "k1#v1|k2#"
const dec = decodePairs(enc); // pairs
import {
hashString,
enumerateShardSuffixes,
shardSuffixFromHash,
} from '@karmaniverous/entity-tools';
const h = hashString('hello'); // 32-bit unsigned number
const hex2 = enumerateShardSuffixes(16, 2); // ["00", ..., "ff"]
const suffix = shardSuffixFromHash(h, 16, 2); // e.g. "a3"
defineTranscodes when introducing any new transcoding map: it provides the strongest DX and prevents silent mismatches.int, fix6, bigint20, timestamp) when you need lexicographic ordering to match numeric ordering.SortOrder descriptors type-safe with defineSortOrder when authoring reusable sort descriptors.