@gabegabegabe/common
v0.3.0
Published
A library of common types and methods
Readme
@gabegabegabe/common
A library of shared TypeScript utilities and type helpers.
Installation
npm install @gabegabegabe/commonUsage
Import all namespaces from the main entry point:
import { dom, promise, random, time, typeGuards } from '@gabegabegabe/common';
import type { models } from '@gabegabegabe/common';Or import individual sub-packages directly:
import { uuid, randomInteger } from '@gabegabegabe/common/random';
import { seconds, minutes } from '@gabegabegabe/common/time';
import { exists } from '@gabegabegabe/common/type-guards';
import type { Immutable, XOR } from '@gabegabegabe/common/models';time
Functions that convert a unit amount to milliseconds.
time.milliseconds(500) // 500
time.seconds(30) // 30_000
time.minutes(5) // 300_000
time.hours(2) // 7_200_000
time.days(1) // 86_400_000
time.weeks(1) // 604_800_000
time.years(1) // 31_557_600_000 (365.25 days)Useful for passing durations to setTimeout, setInterval, cache TTLs, etc.:
setTimeout(callback, time.minutes(5));random
random.uuid() // 'b3d4f1a2-...' (crypto.randomUUID)
random.randomInteger(1, 10) // integer in [1, 10]
random.randomNumber(0.5, 9.5) // float in [0.5, 9.5)
random.randomFromArray(['a', 'b', 'c']) // random elementrandomInteger and randomNumber throw RangeError if min > max.
randomFromArray throws RangeError on an empty array.
typeGuards
const values: Array<number | null | undefined> = [1, null, 2, undefined, 3];
const defined: number[] = values.filter(typeGuards.exists); // [1, 2, 3]exists<T>(item?: T | null): item is T
Returns false for null and undefined, true for everything else — including 0, '', and false.
dom
// Run a callback once the DOM is ready
dom.ready(() => { console.log('ready'); });
// Set the document title
dom.setTitle('My Page');
// Walk up the DOM tree to find the nearest matching ancestor
const panel = dom.parentQuerySelector(buttonEl, '.panel');parentQuerySelector(element, selector)
Like Element.closest() but starts at parentElement, so it never matches the element itself.
promise
// Flush pending microtasks — useful in tests
await promise.flushPromises();flushPromises(): Promise<void>
Resolves after all currently-queued microtasks have run. Awaiting it multiple times drains deeper async chains:
void startSomeAsyncWork();
await promise.flushPromises();
await promise.flushPromises(); // flush a second level of awaits
expect(result).toBe('done');models
Type-only utilities — no runtime code.
import type { models } from '@gabegabegabe/common';
// or individual types:
import type { Immutable, XOR } from '@gabegabegabe/common/models';Immutable<T>
Recursively marks every property and array as readonly.
type Config = Immutable<{ host: string; ports: number[] }>;
// { readonly host: string; readonly ports: readonly number[] }XOR<A, B>
Requires exactly one of two types — not both, not neither.
type Props = XOR<{ href: string }, { onClick: () => void }>;RequireAtLeastOne<T, Keys>
Of the listed optional keys, at least one must be present.
type Search = RequireAtLeastOne<{ id?: number; slug?: string; name?: string }, 'id' | 'slug'>;
// { id: number } | { slug: string } | { id: number; slug: string } (name still optional)RequireOnlyOne<T, Keys>
Of the listed optional keys, exactly one must be present.
type Input = RequireOnlyOne<{ text?: string; html?: string }, 'text' | 'html'>;UnionToIntersection<U>
Converts a union type into an intersection type.
type Merged = UnionToIntersection<{ foo: string } | { bar: number }>;
// { foo: string } & { bar: number }Without<T, U>
Sets all keys in T that are not in U to never. Used internally by XOR.
