Entity Tools provides a compact set of runtime utilities and type-level helpers for working with data models (Entities), sorting, shallow updates, and safe transcoding between values and lexicographically sortable strings.
npm i @karmaniverous/entity-tools
# or: pnpm add @karmaniverous/entity-tools
# or: yarn add @karmaniverous/entity-tools
Runtime utilities
Core types (entities and sorting)
Transcoding types
Type utilities
Full reference: see API docs linked at the top of this README.
Sorting
import { sort, type SortOrder } from '@karmaniverous/entity-tools';
type User = {
id: number;
name: string;
optional?: string | null;
data?: object;
};
const users: User[] = [
{ id: 2, name: 'Adam', optional: 'foo', data: { foo: 'bar' } },
{ id: 3, name: 'Bob', optional: 'bar', data: { bar: 'baz' } },
{ id: 1, name: 'Charlie', optional: null, data: { baz: 'qux' } },
{ id: 4, name: 'Adam' },
];
const order: SortOrder<User> = [
{ property: 'name' },
{ property: 'id', desc: true },
];
const result = sort(users, order);
// [
// { id: 4, name: 'Adam' },
// { id: 2, name: 'Adam', optional: 'foo', data: { foo: 'bar' } },
// { id: 3, name: 'Bob', optional: 'bar', data: { bar: 'baz' } },
// { id: 1, name: 'Charlie', optional: null, data: { baz: 'qux' } },
// ]
Shallow updates
import { updateRecord } 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 = updateRecord(original, patch);
// { id: 1, name: 'Alicia' } // note and extra are removed (null/undefined stripped)
Conditional execution
import { conditionalize } from '@karmaniverous/entity-tools';
const debugLog = conditionalize(console.log, process.env.DEBUG);
debugLog?.('only logs when DEBUG is truthy');
Nil checks
import { isNil, type Nil } from '@karmaniverous/entity-tools';
function takesMaybe(v: unknown): v is Nil {
return isNil(v);
}
Transcoding (encode/decode)
import { defaultTranscodes } from '@karmaniverous/entity-tools';
// Fixed-width integer (sign-prefixed, zero-padded; sorts lexicographically)
const enc = defaultTranscodes.int.encode(-123); // "n0000000000000123"
const dec = defaultTranscodes.int.decode(enc); // -123
// Fixed 6-decimal number
defaultTranscodes.fix6.encode(123.45); // "p0000000123.450000"
defaultTranscodes.fix6.decode('n0000000123.450000'); // -123.45
// Variable width number, boolean, string
defaultTranscodes.number.encode(42); // "42"
defaultTranscodes.boolean.decode('t'); // true
defaultTranscodes.string.encode('hello'); // "hello"
// BigInt (variable) and BigInt20 (fixed width up to 20 digits)
defaultTranscodes.bigint.encode(1234567890123456789n); // "1234567890123456789"
defaultTranscodes.bigint20.encode(-1234567890123456789n); // "n01234567890123456789"
Notes on default transcoding
Type-only helpers (samples)
import type {
MakeOptional,
MakeRequired,
MakeUpdatable,
WithRequiredAndNonNullable,
MutuallyExclusive,
PropertiesOfType,
PropertiesNotOfType,
ReplaceKey,
ReplaceKeys,
} from '@karmaniverous/entity-tools';
type User = { id: number; name: string; note?: string | null };
type OptionalNote = MakeOptional<User, 'note'>;
type RequiredId = WithRequiredAndNonNullable<User, 'id'>;
// Compile-time exclusivity check (returns true or an error-shape).
type Ex = MutuallyExclusive<['a', 'b' | 'c', 'd']>; // true
Built for you with ❤️ on Bali! Find more great tools & templates on my GitHub Profile.