refactor(stdlib): replace source any with unknown/generics

Type guards take `unknown`; walkers/comparators (get/set/isEqual) narrow via
casts; generic defaults and constraints tightened. Truly-idiomatic any-function
constraints and load-bearing type-level any are kept with explanatory comments.
This commit is contained in:
2026-06-15 16:54:50 +07:00
parent d6c6a62557
commit 425a7bc6e7
21 changed files with 124 additions and 107 deletions
+21 -21
View File
@@ -30,7 +30,7 @@ if (error) {
<!-- Hero -->
<div class="prose-docs">
<h1>@robonen/stdlib</h1>
<p class="text-lg text-(--fg-muted)">
<p class="text-lg text-fg-muted">
A platform-independent standard library of tools, utilities, and helpers for TypeScript
arrays, async, math, data structures, and patterns, all tree-shakeable and fully typed.
</p>
@@ -48,30 +48,30 @@ if (error) {
<!-- Feature highlights -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div class="rounded-lg border border-(--border) bg-(--bg-subtle) p-5">
<h3 class="text-sm font-semibold text-(--fg) mb-1.5">Fully typed</h3>
<p class="text-sm text-(--fg-muted) leading-relaxed">
<div class="rounded-lg border border-border bg-bg-subtle p-5">
<h3 class="text-sm font-semibold text-fg mb-1.5">Fully typed</h3>
<p class="text-sm text-fg-muted leading-relaxed">
Generic signatures preserve element and key types end to end, so inference keeps
working through <code>groupBy</code>, <code>partition</code>, <code>zip</code>, and friends.
</p>
</div>
<div class="rounded-lg border border-(--border) bg-(--bg-subtle) p-5">
<h3 class="text-sm font-semibold text-(--fg) mb-1.5">Zero dependencies</h3>
<p class="text-sm text-(--fg-muted) leading-relaxed">
<div class="rounded-lg border border-border bg-bg-subtle p-5">
<h3 class="text-sm font-semibold text-fg mb-1.5">Zero dependencies</h3>
<p class="text-sm text-fg-muted leading-relaxed">
No transitive dependencies and no platform assumptions. The same code runs in Node,
the browser, Deno, Bun, and edge runtimes.
</p>
</div>
<div class="rounded-lg border border-(--border) bg-(--bg-subtle) p-5">
<h3 class="text-sm font-semibold text-(--fg) mb-1.5">Tree-shakeable</h3>
<p class="text-sm text-(--fg-muted) leading-relaxed">
<div class="rounded-lg border border-border bg-bg-subtle p-5">
<h3 class="text-sm font-semibold text-fg mb-1.5">Tree-shakeable</h3>
<p class="text-sm text-fg-muted leading-relaxed">
Each utility is a standalone export with no shared side effects. Import a single
function and ship only that function.
</p>
</div>
<div class="rounded-lg border border-(--border) bg-(--bg-subtle) p-5">
<h3 class="text-sm font-semibold text-(--fg) mb-1.5">Batteries included</h3>
<p class="text-sm text-(--fg-muted) leading-relaxed">
<div class="rounded-lg border border-border bg-bg-subtle p-5">
<h3 class="text-sm font-semibold text-fg mb-1.5">Batteries included</h3>
<p class="text-sm text-fg-muted leading-relaxed">
Beyond array and math helpers you get data structures
(<code>Deque</code>, <code>BinaryHeap</code>, <code>LinkedList</code>) and patterns
(<code>StateMachine</code>, <code>PubSub</code>, <code>Command</code>).
@@ -126,16 +126,16 @@ if (error) {
</div>
<!-- Where to next -->
<div class="rounded-lg border border-(--border) bg-(--bg-elevated) p-5">
<h2 class="text-base font-semibold text-(--fg) mb-2">Where to next</h2>
<p class="text-sm text-(--fg-muted) mb-3">
<div class="rounded-lg border border-border bg-bg-elevated p-5">
<h2 class="text-base font-semibold text-fg mb-2">Where to next</h2>
<p class="text-sm text-fg-muted mb-3">
Browse the full API reference below, or jump straight to a popular utility:
</p>
<ul class="flex flex-wrap gap-2 m-0 p-0 list-none">
<li>
<NuxtLink
to="/stdlib/group-by"
class="inline-flex items-center rounded-md border border-(--border) bg-(--bg-subtle) px-3 py-1.5 text-sm text-(--accent-text) hover:bg-(--bg-inset) focus:ring-(--ring)"
class="inline-flex items-center rounded-md border border-border bg-bg-subtle px-3 py-1.5 text-sm text-accent-text hover:bg-bg-inset focus:ring-ring"
>
groupBy
</NuxtLink>
@@ -143,7 +143,7 @@ if (error) {
<li>
<NuxtLink
to="/stdlib/try-it"
class="inline-flex items-center rounded-md border border-(--border) bg-(--bg-subtle) px-3 py-1.5 text-sm text-(--accent-text) hover:bg-(--bg-inset) focus:ring-(--ring)"
class="inline-flex items-center rounded-md border border-border bg-bg-subtle px-3 py-1.5 text-sm text-accent-text hover:bg-bg-inset focus:ring-ring"
>
tryIt
</NuxtLink>
@@ -151,7 +151,7 @@ if (error) {
<li>
<NuxtLink
to="/stdlib/retry"
class="inline-flex items-center rounded-md border border-(--border) bg-(--bg-subtle) px-3 py-1.5 text-sm text-(--accent-text) hover:bg-(--bg-inset) focus:ring-(--ring)"
class="inline-flex items-center rounded-md border border-border bg-bg-subtle px-3 py-1.5 text-sm text-accent-text hover:bg-bg-inset focus:ring-ring"
>
retry
</NuxtLink>
@@ -159,7 +159,7 @@ if (error) {
<li>
<NuxtLink
to="/stdlib/clamp"
class="inline-flex items-center rounded-md border border-(--border) bg-(--bg-subtle) px-3 py-1.5 text-sm text-(--accent-text) hover:bg-(--bg-inset) focus:ring-(--ring)"
class="inline-flex items-center rounded-md border border-border bg-bg-subtle px-3 py-1.5 text-sm text-accent-text hover:bg-bg-inset focus:ring-ring"
>
clamp
</NuxtLink>
@@ -167,7 +167,7 @@ if (error) {
<li>
<NuxtLink
to="/stdlib/debounce"
class="inline-flex items-center rounded-md border border-(--border) bg-(--bg-subtle) px-3 py-1.5 text-sm text-(--accent-text) hover:bg-(--bg-inset) focus:ring-(--ring)"
class="inline-flex items-center rounded-md border border-border bg-bg-subtle px-3 py-1.5 text-sm text-accent-text hover:bg-bg-inset focus:ring-ring"
>
debounce
</NuxtLink>
+2 -2
View File
@@ -1,3 +1,3 @@
import { base, compose, imports, stylistic, typescript } from '@robonen/eslint';
import { base, compose, imports, stylistic, tests, typescript } from '@robonen/eslint';
export default compose(base, typescript, imports, stylistic);
export default compose(base, typescript, imports, stylistic, tests);
+1 -1
View File
@@ -22,7 +22,7 @@ export function zip<A, B>(a: A[], b: B[]): Array<[A, B]>;
export function zip<A, B, C>(a: A[], b: B[], c: C[]): Array<[A, B, C]>;
export function zip<A, B, C, D>(a: A[], b: B[], c: C[], d: D[]): Array<[A, B, C, D]>;
export function zip<A, B, C, D, E>(a: A[], b: B[], c: C[], d: D[], e: E[]): Array<[A, B, C, D, E]>;
export function zip(...arrays: any[][]): any[][] {
export function zip(...arrays: unknown[][]): unknown[][] {
if (arrays.length === 0)
return [];
+4 -2
View File
@@ -6,7 +6,7 @@ export interface AsyncPoolOptions {
signal?: AbortSignal;
}
interface PoolEntry<T = any> {
interface PoolEntry<T = unknown> {
task: (signal: AbortSignal) => Promise<T>;
resolve: (value: T) => void;
reject: (reason: unknown) => void;
@@ -115,7 +115,9 @@ export class AsyncPool {
reject(this.signal.reason);
return promise;
}
const entry = { task, resolve, reject } as PoolEntry<T>;
// Stored in a homogeneous queue: the per-call T is erased to PoolEntry<unknown>.
// run() resolves/rejects with unknown values, so this is sound at runtime.
const entry = { task, resolve, reject } as unknown as PoolEntry;
if (this.activeCount < this.limit) {
this.run(entry);
}
+4 -4
View File
@@ -11,13 +11,13 @@ export interface RetryOptions {
export type RetryFunction<Return> = (
args: {
count: number;
stop: (error: any) => void;
stop: (error: unknown) => void;
},
) => Promise<Return>;
class RetryEarlyExitError {
cause: any;
constructor(cause: any) {
cause: unknown;
constructor(cause: unknown) {
this.cause = cause;
}
}
@@ -62,7 +62,7 @@ export async function retry<Return>(
const delayFn = isFunction(delay) ? delay : null;
const delayMs = delayFn ? 0 : delay as number;
const stop = (error?: any): never => {
const stop = (error?: unknown): never => {
throw new RetryEarlyExitError(error);
};
+4 -4
View File
@@ -1,4 +1,4 @@
export type TryItReturn<Return> = Return extends PromiseLike<any>
export type TryItReturn<Return> = Return extends PromiseLike<unknown>
? Promise<{ error: Error; data: undefined } | { error: undefined; data: Awaited<Return> }>
: { error: Error; data: undefined } | { error: undefined; data: Return };
@@ -7,11 +7,11 @@ function isThenable(value: unknown): value is PromiseLike<unknown> {
&& typeof (value as PromiseLike<unknown>).then === 'function';
}
function onResolve(data: any) {
function onResolve(data: unknown) {
return { error: undefined, data };
}
function onReject(error: any) {
function onReject(error: unknown) {
return { error, data: undefined };
}
@@ -32,7 +32,7 @@ function onReject(error: any) {
*
* @since 0.0.3
*/
export function tryIt<Args extends any[], Return>(
export function tryIt<Args extends unknown[], Return>(
fn: (...args: Args) => Return,
) {
return (...args: Args): TryItReturn<Return> => {
+8 -5
View File
@@ -7,7 +7,10 @@ export type ExtractFromObject<O extends Record<PropertyKey, unknown>, K>
? NonNullable<O>[K]
: never;
export type ExtractFromArray<A extends readonly any[], K>
export type ExtractFromArray<A extends readonly unknown[], K>
// `any[]` (not `unknown[]`) is load-bearing: `any[] extends number[]` is true while
// `unknown[] extends number[]` is false. This distinguishes a general array (widen the
// element with `undefined`) from a fixed tuple (resolve the exact element at index K).
= any[] extends A
? A extends ReadonlyArray<infer T>
? T | undefined
@@ -22,7 +25,7 @@ export type ExtractFromCollection<O, K>
: K extends [infer Key, ...infer Rest]
? O extends Record<PropertyKey, unknown>
? ExtractFromCollection<ExtractFromObject<O, Key>, Rest>
: O extends readonly any[]
: O extends readonly unknown[]
? ExtractFromCollection<ExtractFromArray<O, Key>, Rest>
: never
: never;
@@ -46,7 +49,7 @@ export type Get<O, K> = ExtractFromCollection<O, Path<K>>;
* @since 0.0.4
*/
export function get<O extends Collection, K extends string>(obj: O, path: K): Get<O, K> | undefined {
let value: any = obj;
let value: unknown = obj;
let start = 0;
// Walk the path without allocating an intermediate array of segments.
@@ -58,9 +61,9 @@ export function get<O extends Collection, K extends string>(obj: O, path: K): Ge
if (value === null || value === undefined)
return undefined;
value = value[path.slice(start, i)];
value = (value as Record<string, unknown>)[path.slice(start, i)];
start = i + 1;
}
return value;
return value as Get<O, K> | undefined;
}
+2 -2
View File
@@ -27,7 +27,7 @@ export function set<O extends Collection>(obj: O, path: string, value: unknown):
const keys = path.split('.');
const lastKey = keys[keys.length - 1]!;
let current: any = obj;
let current = obj as Record<PropertyKey, unknown>;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i]!;
@@ -38,7 +38,7 @@ export function set<O extends Collection>(obj: O, path: string, value: unknown):
if (next === null || typeof next !== 'object')
current[key] = NUMERIC_SEGMENT.test(keys[i + 1]!) ? [] : {};
current = current[key];
current = current[key] as Record<PropertyKey, unknown>;
}
current[lastKey] = value;
+2 -2
View File
@@ -1,4 +1,4 @@
function equals(a: any, b: any, seen: WeakMap<object, unknown>): boolean {
function equals(a: unknown, b: unknown, seen: WeakMap<object, unknown>): boolean {
if (a === b)
return true;
@@ -65,7 +65,7 @@ function equals(a: any, b: any, seen: WeakMap<object, unknown>): boolean {
return false;
for (const key of aKeys) {
if (!Object.prototype.hasOwnProperty.call(b, key) || !equals(a[key], b[key], seen))
if (!Object.prototype.hasOwnProperty.call(b, key) || !equals((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key], seen))
return false;
}
+8 -8
View File
@@ -14,15 +14,15 @@ import type { AnyFunction } from '../../types';
*
* @since 0.0.10
*/
export function compose<A extends any[], B>(ab: (...a: A) => B): (...a: A) => B;
export function compose<A extends any[], B, C>(bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => C;
export function compose<A extends any[], B, C, D>(cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => D;
export function compose<A extends any[], B, C, D, E>(de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => E;
export function compose<A extends any[], B, C, D, E, F>(ef: (e: E) => F, de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => F;
export function compose<A extends any[], B, C, D, E, F, G>(fg: (f: F) => G, ef: (e: E) => F, de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => G;
export function compose<A extends any[], B, C, D, E, F, G, H>(gh: (g: G) => H, fg: (f: F) => G, ef: (e: E) => F, de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => H;
export function compose<A extends unknown[], B>(ab: (...a: A) => B): (...a: A) => B;
export function compose<A extends unknown[], B, C>(bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => C;
export function compose<A extends unknown[], B, C, D>(cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => D;
export function compose<A extends unknown[], B, C, D, E>(de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => E;
export function compose<A extends unknown[], B, C, D, E, F>(ef: (e: E) => F, de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => F;
export function compose<A extends unknown[], B, C, D, E, F, G>(fg: (f: F) => G, ef: (e: E) => F, de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => G;
export function compose<A extends unknown[], B, C, D, E, F, G, H>(gh: (g: G) => H, fg: (f: F) => G, ef: (e: E) => F, de: (d: D) => E, cd: (c: C) => D, bc: (b: B) => C, ab: (...a: A) => B): (...a: A) => H;
export function compose(...fns: AnyFunction[]): AnyFunction {
return function (this: unknown, ...args: any[]) {
return function (this: unknown, ...args: unknown[]) {
const last = fns.length - 1;
if (last < 0)
+8 -8
View File
@@ -14,15 +14,15 @@ import type { AnyFunction } from '../../types';
*
* @since 0.0.10
*/
export function pipe<A extends any[], B>(ab: (...a: A) => B): (...a: A) => B;
export function pipe<A extends any[], B, C>(ab: (...a: A) => B, bc: (b: B) => C): (...a: A) => C;
export function pipe<A extends any[], B, C, D>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...a: A) => D;
export function pipe<A extends any[], B, C, D, E>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): (...a: A) => E;
export function pipe<A extends any[], B, C, D, E, F>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): (...a: A) => F;
export function pipe<A extends any[], B, C, D, E, F, G>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): (...a: A) => G;
export function pipe<A extends any[], B, C, D, E, F, G, H>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H): (...a: A) => H;
export function pipe<A extends unknown[], B>(ab: (...a: A) => B): (...a: A) => B;
export function pipe<A extends unknown[], B, C>(ab: (...a: A) => B, bc: (b: B) => C): (...a: A) => C;
export function pipe<A extends unknown[], B, C, D>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D): (...a: A) => D;
export function pipe<A extends unknown[], B, C, D, E>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E): (...a: A) => E;
export function pipe<A extends unknown[], B, C, D, E, F>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F): (...a: A) => F;
export function pipe<A extends unknown[], B, C, D, E, F, G>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G): (...a: A) => G;
export function pipe<A extends unknown[], B, C, D, E, F, G, H>(ab: (...a: A) => B, bc: (b: B) => C, cd: (c: C) => D, de: (d: D) => E, ef: (e: E) => F, fg: (f: F) => G, gh: (g: G) => H): (...a: A) => H;
export function pipe(...fns: AnyFunction[]): AnyFunction {
return function (this: unknown, ...args: any[]) {
return function (this: unknown, ...args: unknown[]) {
if (fns.length === 0)
return args[0];
@@ -124,6 +124,9 @@ export function createAsyncMachine<
export function createAsyncMachine(config: {
initial: string;
context?: unknown;
// Overload-implementation signature: the typed overloads above expose the real
// per-context API; `any` here accepts every concrete `AsyncStateNodeConfig<C>`
// (contravariant in `C`, so `unknown` would reject them).
states: Record<string, AsyncStateNodeConfig<any>>;
}): AsyncStateMachine {
return new AsyncStateMachine(
@@ -125,6 +125,9 @@ export function createMachine<
export function createMachine(config: {
initial: string;
context?: unknown;
// Overload-implementation signature: the typed overloads above expose the real
// per-context API; `any` here accepts every concrete `SyncStateNodeConfig<C>`
// (contravariant in `C`, so `unknown` would reject them).
states: Record<string, SyncStateNodeConfig<any>>;
}): StateMachine {
return new StateMachine(
@@ -58,7 +58,7 @@ export type AsyncStateNodeConfig<Context> = StateNodeConfig<Context, MaybePromis
export type ExtractStates<T> = keyof T & string;
export type ExtractEvents<T> = {
[K in keyof T]: T[K] extends { readonly on?: Readonly<Record<infer E extends string, any>> }
[K in keyof T]: T[K] extends { readonly on?: Readonly<Record<infer E extends string, unknown>> }
? E
: never;
}[keyof T];
+3 -2
View File
@@ -14,7 +14,7 @@ export interface BinaryHeapOptions<T> {
* @param {number} b Second element
* @returns {number} Negative if a < b, positive if a > b, zero if equal
*/
const defaultComparator: Comparator<any> = (a: number, b: number) => a - b;
const defaultComparator: Comparator<number> = (a: number, b: number) => a - b;
/**
* @name BinaryHeap
@@ -49,7 +49,8 @@ export class BinaryHeap<T> implements BinaryHeapLike<T> {
* @param {BinaryHeapOptions<T>} [options] Heap configuration
*/
constructor(initialValues?: T[] | T, options?: BinaryHeapOptions<T>) {
this.comparator = options?.comparator ?? defaultComparator;
// Numeric default; cast bridges it to the caller's `T` when no comparator is given.
this.comparator = options?.comparator ?? (defaultComparator as Comparator<T>);
if (initialValues !== null && initialValues !== undefined) {
const items = isArray(initialValues) ? initialValues : [initialValues];
+2 -2
View File
@@ -3,9 +3,9 @@
* @category Types
* @description To string any value
*
* @param {any} value
* @param {unknown} value
* @returns {string}
*
* @since 0.0.2
*/
export const toString = (value: any): string => Object.prototype.toString.call(value);
export const toString = (value: unknown): string => Object.prototype.toString.call(value);
-1
View File
@@ -38,7 +38,6 @@ describe('complex', () => {
});
it('true for class instances and null-prototype objects', () => {
// eslint-disable-next-line @typescript-eslint/no-extraneous-class -- fixture for the instance check
class Foo {}
expect(isObject(new Foo())).toBe(true);
+25 -25
View File
@@ -5,117 +5,117 @@ import { toString } from './casts';
* @category Types
* @description Check if a value is an array
*
* @param {any} value
* @returns {value is any[]}
* @param {unknown} value
* @returns {value is T[]}
*
* @since 0.0.2
*/
export const isArray = (value: any): value is any[] => Array.isArray(value);
export const isArray = <T = unknown>(value: unknown): value is T[] => Array.isArray(value);
/**
* @name isObject
* @category Types
* @description Check if a value is an object
*
* @param {any} value
* @param {unknown} value
* @returns {value is object}
*
* @since 0.0.2
*/
export const isObject = (value: any): value is object => toString(value) === '[object Object]';
export const isObject = (value: unknown): value is object => toString(value) === '[object Object]';
/**
* @name isRegExp
* @category Types
* @description Check if a value is a regexp
*
* @param {any} value
* @param {unknown} value
* @returns {value is RegExp}
*
* @since 0.0.2
*/
export const isRegExp = (value: any): value is RegExp => toString(value) === '[object RegExp]';
export const isRegExp = (value: unknown): value is RegExp => toString(value) === '[object RegExp]';
/**
* @name isDate
* @category Types
* @description Check if a value is a date
*
* @param {any} value
* @param {unknown} value
* @returns {value is Date}
*
* @since 0.0.2
*/
export const isDate = (value: any): value is Date => toString(value) === '[object Date]';
export const isDate = (value: unknown): value is Date => toString(value) === '[object Date]';
/**
* @name isError
* @category Types
* @description Check if a value is an error
*
* @param {any} value
* @param {unknown} value
* @returns {value is Error}
*
* @since 0.0.2
*/
export const isError = (value: any): value is Error => toString(value) === '[object Error]';
export const isError = (value: unknown): value is Error => toString(value) === '[object Error]';
/**
* @name isPromise
* @category Types
* @description Check if a value is a promise
*
* @param {any} value
* @returns {value is Promise<any>}
* @param {unknown} value
* @returns {value is Promise<unknown>}
*
* @since 0.0.2
*/
export const isPromise = (value: any): value is Promise<any> => toString(value) === '[object Promise]';
export const isPromise = (value: unknown): value is Promise<unknown> => toString(value) === '[object Promise]';
/**
* @name isMap
* @category Types
* @description Check if a value is a map
*
* @param {any} value
* @returns {value is Map<any, any>}
* @param {unknown} value
* @returns {value is Map<unknown, unknown>}
*
* @since 0.0.2
*/
export const isMap = (value: any): value is Map<any, any> => toString(value) === '[object Map]';
export const isMap = (value: unknown): value is Map<unknown, unknown> => toString(value) === '[object Map]';
/**
* @name isSet
* @category Types
* @description Check if a value is a set
*
* @param {any} value
* @returns {value is Set<any>}
* @param {unknown} value
* @returns {value is Set<unknown>}
*
* @since 0.0.2
*/
export const isSet = (value: any): value is Set<any> => toString(value) === '[object Set]';
export const isSet = (value: unknown): value is Set<unknown> => toString(value) === '[object Set]';
/**
* @name isWeakMap
* @category Types
* @description Check if a value is a weakmap
*
* @param {any} value
* @returns {value is WeakMap<object, any>}
* @param {unknown} value
* @returns {value is WeakMap<object, unknown>}
*
* @since 0.0.2
*/
export const isWeakMap = (value: any): value is WeakMap<object, any> => toString(value) === '[object WeakMap]';
export const isWeakMap = (value: unknown): value is WeakMap<object, unknown> => toString(value) === '[object WeakMap]';
/**
* @name isWeakSet
* @category Types
* @description Check if a value is a weakset
*
* @param {any} value
* @param {unknown} value
* @returns {value is WeakSet<object>}
*
* @since 0.0.2
*/
export const isWeakSet = (value: any): value is WeakSet<object> => toString(value) === '[object WeakSet]';
export const isWeakSet = (value: unknown): value is WeakSet<object> => toString(value) === '[object WeakSet]';
+17 -16
View File
@@ -3,93 +3,94 @@
* @category Types
* @description Check if a value is a boolean
*
* @param {any} value
* @param {unknown} value
* @returns {value is boolean}
*
* @since 0.0.2
*/
export const isBoolean = (value: any): value is boolean => typeof value === 'boolean';
export const isBoolean = (value: unknown): value is boolean => typeof value === 'boolean';
/**
* @name isFunction
* @category Types
* @description Check if a value is a function
*
* @param {any} value
* @param {unknown} value
* @returns {value is Function}
*
* @since 0.0.2
*/
export const isFunction = <T extends (...args: any[]) => any>(value: any): value is T => typeof value === 'function';
// `(...args: any[]) => any` is the idiomatic "any function" constraint here; `unknown` would reject legitimate function shapes at call sites.
export const isFunction = <T extends (...args: any[]) => any>(value: unknown): value is T => typeof value === 'function';
/**
* @name isNumber
* @category Types
* @description Check if a value is a number
*
* @param {any} value
* @param {unknown} value
* @returns {value is number}
*
* @since 0.0.2
*/
export const isNumber = (value: any): value is number => typeof value === 'number';
export const isNumber = (value: unknown): value is number => typeof value === 'number';
/**
* @name isBigInt
* @category Types
* @description Check if a value is a bigint
*
* @param {any} value
* @param {unknown} value
* @returns {value is bigint}
*
* @since 0.0.2
*/
export const isBigInt = (value: any): value is bigint => typeof value === 'bigint';
export const isBigInt = (value: unknown): value is bigint => typeof value === 'bigint';
/**
* @name isString
* @category Types
* @description Check if a value is a string
*
* @param {any} value
* @param {unknown} value
* @returns {value is string}
*
* @since 0.0.2
*/
export const isString = (value: any): value is string => typeof value === 'string';
export const isString = (value: unknown): value is string => typeof value === 'string';
/**
* @name isSymbol
* @category Types
* @description Check if a value is a symbol
*
* @param {any} value
* @param {unknown} value
* @returns {value is symbol}
*
* @since 0.0.2
*/
export const isSymbol = (value: any): value is symbol => typeof value === 'symbol';
export const isSymbol = (value: unknown): value is symbol => typeof value === 'symbol';
/**
* @name isUndefined
* @category Types
* @description Check if a value is a undefined
*
* @param {any} value
* @param {unknown} value
* @returns {value is undefined}
*
* @since 0.0.2
*/
export const isUndefined = (value: any): value is undefined => value === undefined;
export const isUndefined = (value: unknown): value is undefined => value === undefined;
/**
* @name isNull
* @category Types
* @description Check if a value is a null
*
* @param {any} value
* @param {unknown} value
* @returns {value is null}
*
* @since 0.0.2
*/
export const isNull = (value: any): value is null => value === null;
export const isNull = (value: unknown): value is null => value === null;
+4 -1
View File
@@ -1,7 +1,10 @@
/**
* A collection definition
*/
export type Collection = Record<PropertyKey, any> | any[];
// `any[]` is kept (not `unknown[]`): as the `O extends Collection` constraint in `get`/`set`,
// `unknown[]` would reject arrays whose elements sit in contravariant positions (e.g. the
// `CircularBuffer<PoolEntry>` used by `async/pool`), breaking compilation outside this file.
export type Collection = Record<PropertyKey, unknown> | any[];
/**
* Parse a collection path string into an array of keys
+2
View File
@@ -1,6 +1,8 @@
/**
* Any function
*/
// `(...args: any[]) => any` is the idiomatic "any function" constraint; `unknown`
// would reject legitimate function shapes when used as `T extends AnyFunction`.
export type AnyFunction = (...args: any[]) => any;
/**