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:
+21
-21
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 [];
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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> => {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user