@zgeoff/std
v0.4.3
Published
Small, dependency-free TypeScript helpers shared across the zgeoff repos
Readme
@zgeoff/std
Small, dependency-free TypeScript helpers that more than one zgeoff repo needs. Each helper is one file with its test beside it, exported from the package root unless it needs Bun, and named by the shared function-naming rules.
Install
bun add @zgeoff/stdHelpers
toExactOptional
Returns a copy of an object without the keys whose value is undefined, typed so the copy fits a
type with optional properties under exactOptionalPropertyTypes. It replaces the conditional
spread, ...(x === undefined ? {} : { x }), that such code otherwise writes per key.
import { toExactOptional } from '@zgeoff/std';
const label: string | undefined = readLabel();
// { label: string | undefined; retries: number } does not fit the type, but
// toExactOptional's { label?: string; retries: number } does.
const options: { label?: string; retries: number } = toExactOptional({ label, retries: 3 });Own enumerable keys are copied, symbols included, as an object spread would. null values stay,
falsy values such as 0 and '' stay, and the input object is left untouched. A union input maps
member by member, so each member keeps its own keys.
isRecord
Tells whether a value is a plain keyed object, and narrows it to Record<string, unknown>, so code
that reads parsed JSON can index it. An array or null is not a record.
import { isRecord } from '@zgeoff/std';
const parsed: unknown = JSON.parse(text);
const name = isRecord(parsed) ? parsed['name'] : undefined;isOneOf
Tells whether a value is one of a list of values, and narrows it to the list's element type, so a
string read from outside the program becomes a literal union without a cast. It compares with
Array.prototype.includes, so NaN matches NaN.
import { isOneOf } from '@zgeoff/std';
const sizes = ['small', 'large'] as const;
const size = isOneOf(input, sizes) ? input : 'small';readOptionalText
Reads a file's text, or returns undefined when the file or a folder on its path does not exist. It
reads to the end of the file, so a procfs or cgroupfs file that reports a size of 0 still reads in
full. Any other failure, such as a path that names a folder, throws.
import { readOptionalText } from '@zgeoff/std';
const lefthook = await readOptionalText('lefthook.yml');writeStdout
Writes a text to stdout as it is, with no newline added. Pass it as the writeOutput of a command's
options at its entry point, so a test hands in its own writer.
import { writeStdout } from '@zgeoff/std';
process.exitCode = runCheck({ cwd: process.cwd(), writeOutput: writeStdout });withFileLock
Runs a callback under an exclusive lock on a file that other processes share. It needs Bun, so
import it from @zgeoff/std/with-file-lock; its doc
covers the rest.
Typed helpers
Each typed helper holds the one type assertion that its job needs, because TypeScript cannot prove
the type it returns. toExactOptional holds one for the same reason. The assertion carries an
approved disable comment, so code that calls the helper needs no assertion of its own.
The typed helpers are machineTypes, pick, mergeDeep, toTagged and toReadonlyDeep.
The std typed helpers doc describes each one, with
an example.
