Universal Utilities
These APIs are available from @carry0987/utils and are safe to use in browser code, Node.js scripts, and SSR-oriented modules unless otherwise noted.
Common value helpers
The commonUtils namespace and direct exports provide the same functions.
Type and shape checks
isDefined(value)narrows awaynullandundefined.isObject(value)accepts plain objects and rejects arrays.isFunction(value),isString(value),isNumber(value),isBoolean(value), andisArray(value)provide lightweight runtime checks.isEmpty(value)treats empty strings, empty arrays, empty objects,null, andundefinedas empty, but keeps0as non-empty.
Cloning and merging
shallowClone(value)clones arrays and objects while preserving object prototypes.deepClone(value)recursively clones nested arrays and objects.shallowMerge(target, ...sources)replaces top-level keys.deepMerge(target, ...sources)recursively merges nested objects and arrays.shallowEqual(a, b)compares top-level keys by reference/value.deepEqual(a, b)recursively compares nested structures, arrays, maps, sets, and dates.
Example:
import { deepClone, deepEqual, deepMerge, shallowMerge } from '@carry0987/utils';
const original = { filters: { status: 'draft' }, tags: ['docs'] };
const copied = deepClone(original);
const merged = deepMerge({ page: 1 }, { filters: { status: 'published' } });
const flat = shallowMerge({ page: 1, sort: 'asc' }, { sort: 'desc' });
console.log(deepEqual(original, copied));
console.log(merged, flat);
IDs and random values
generateRandom(length = 8)returns a lowercase alphanumeric string.generateUUID()returns a UUID v4-style string.
URL helpers
Utils-JS includes helpers for both search parameters and hash fragments.
Reading values
getUrlParam(name, url?)reads a search parameter and ignores hash values.getHashParam(name?, url?)reads a hash parameter, or returns the plain hash fragment when called without a key.isValidURL(url)validates whether the string can be parsed by theURLconstructor.
Writing values
setUrlParam(url, params, overwrite = true)updates query string values.setHashParam(url, params, overwrite = true)updates hash parameters or replaces the hash with a plain string.- Both setters support an object form with
ignoresegments so preserved routing fragments or custom tokens are not overwritten.
Example:
import { getHashParam, getUrlParam, setHashParam, setUrlParam } from '@carry0987/utils';
const searchUrl = setUrlParam('https://example.com/posts?page=1', {
page: 2,
sort: 'recent',
});
const hashUrl = setHashParam(
{
url: 'https://example.com/#/route&tab=overview',
ignore: '/route',
},
{ tab: 'api', panel: 'examples' }
);
console.log(getUrlParam('page', searchUrl));
console.log(getHashParam('tab', hashUrl));
Request helpers
fetchUtils wraps the Fetch API with a small callback-friendly layer.
doFetch(options)
Returns the raw Response and optionally runs lifecycle callbacks:
beforeSend()before executing the requestsuccess(data)after a successful responseerror(err)if the request fails or returns a non-OK status
For GET requests, object bodies are converted into URL parameters. For POST, PUT, and DELETE, object bodies are JSON-stringified unless a FormData instance is provided.
sendData(options)
Builds on doFetch() and returns parsed response data directly.
- JSON responses are parsed into objects.
- Non-JSON responses are returned as plain text.
- Empty success responses return
null.
sendFormData(options) and aliases
sendFormData()returnstrueon success andfalseon failure.fetchDatais an alias ofsendData.sendFormis an alias ofsendFormData.
Example:
import { doFetch, sendData, sendFormData } from '@carry0987/utils';
await doFetch({
url: 'https://example.com/api/ping',
success(data) {
console.log('Ping result:', data);
},
});
const created = await sendData<{ message: string }>({
url: 'https://example.com/api/posts',
method: 'POST',
data: { title: 'Hello', published: true },
});
const uploaded = await sendFormData({
url: 'https://example.com/api/upload',
data: { file: new File(['hello'], 'hello.txt') },
});
FormData helpers
The formUtils module is useful when requests need nested form encoding.
appendFormData({ data, parentKey }, formData?)appends nested values into an existingFormDatainstance.encodeFormData(data)converts objects, files, blobs, or an existingFormDatainstance into aFormDatapayload.decodeFormData(formData)converts aFormDatainstance back into a plain object, combining repeated keys into arrays.formDataToURLParams(formData)convertsFormDatafields into a plain parameter object.bodyToURLParams(body)convertsFormDataor plain objects into URL parameter objects, serializing complex values to JSON strings.
Example:
import { bodyToURLParams, decodeFormData, encodeFormData } from '@carry0987/utils';
const formData = encodeFormData({
title: 'Guide',
metadata: { category: 'docs', priority: 1 },
});
const restored = decodeFormData(formData);
const params = bodyToURLParams({ filter: { status: 'published' }, page: 2 });
console.log(restored, params);
Execution helpers
throttle(fn, wait, options)limits how often a function can run.debounce(fn, wait, options)delays execution until calls settle and returns aPromisefor the final result.
debounce() resolves all pending calls with the final invocation result, which makes it useful for autosave and search suggestion flows.
Example:
import { debounce, throttle } from '@carry0987/utils';
const logScroll = throttle(() => {
console.log('scroll');
}, 100, { trailing: true });
const saveDraft = debounce(async (value: string) => {
return `saved:${value}`;
}, 200, { maxWait: 1000 });
Error helpers
reportError(...args)forwards values toconsole.error.throwError(message)throws a newError.assertNever(value, message?)is useful for exhaustive switch handling.
Version export
version is exported from both runtime entrypoints. It is replaced at build time and can be used for diagnostics or support metadata.