/* eslint-disable @typescript-eslint/no-explicit-any */ // Named exports — no declare global. Import explicitly or use via @alwatr/core / @alwatr/flux. // ─── Primitives ────────────────────────────────────────────────────────────── /** * Union of all JavaScript primitive types. */ export type Primitive = string | number | bigint | boolean | symbol | null | undefined; /** * Union of all JavaScript falsy values. * * @example * function isFalsy(v: unknown): v is Falsy { * return !v; * } */ export type Falsy = false | '' | 0 | 0n | null | undefined; /** * A value that is either `null` or `undefined`. * Useful for guard clauses: `if (value == null)`. */ export type Nullish = null | undefined; // ─── Functions & Classes ───────────────────────────────────────────────────── /** * Generic function type. * * @template Args - Tuple of argument types. Defaults to `unknown[]`. * @template R - Return type. Defaults to `unknown`. * * @example * type Handler = Func<[string, number], boolean>; */ export type Func = (...args: Args) => R; /** Any callable — equivalent to `Func` with no constraints. */ export type AnyFunc = Func; /** A function that returns `void`. */ export type VoidFunc = Func; /** A zero-argument function that returns `void`. */ export type NoopFunc = () => Awaitable; /** * Removes the first parameter from a function type. * * @example * type MyFunc = (ctx: Context, id: string) => void; * type WithoutCtx = OmitFirstParam; // (id: string) => void */ export type OmitFirstParam = F extends (_first: any, ...args: infer A) => infer R ? (...args: A) => R : never; /** * A class constructor type. * * @template T - The instance type produced by `new`. * @template TArgs - Constructor argument tuple. Defaults to `any[]`. * * @example * function create(Ctor: Class): T { * return new Ctor(); * } */ export type Class = new (...args: TArgs) => T; // ─── Wrappers & Modifiers ──────────────────────────────────────────────────── /** * `T | null` — value is present or explicitly absent. */ export type Nullable = T | null; /** * `T | undefined` — value may not have been set yet. * For "present or explicitly absent" use `Nullable`. */ export type Maybe = T | undefined; /** * `T | Promise` — value may be synchronous or asynchronous. * * @example * async function run(fn: () => Awaitable) { * await fn(); * } */ export type Awaitable = T | Promise; /** * `T | T[]` — accepts a single item or a mutable array. */ export type SingleOrArray = T | T[]; /** * `T | readonly T[]` — accepts a single item or a readonly array. */ export type SingleOrReadonlyArray = T | readonly T[]; /** * Excludes `undefined` from `T` while keeping `null`. * Use the built-in `NonNullable` to exclude both `null` and `undefined`. */ export type NonUndefined = T extends undefined ? never : T; /** * Removes `readonly` from all properties of `T`. * * @example * type Config = { readonly port: number }; * type MutableConfig = Mutable; // { port: number } */ export type Mutable = { -readonly [P in keyof T]: T[P]; }; /** * Makes every property of `T` required and strips `null | undefined` from each value type. * Stricter than the built-in `Required`. * * @example * type User = { name?: string | null; age?: number }; * type StrictUser = StrictlyRequired; // { name: string; age: number } */ export type StrictlyRequired = { [P in keyof T]-?: NonNullable; }; // ─── Dictionaries ──────────────────────────────────────────────────────────── /** * A sparse string-keyed map — any key may be absent. * Prefer over `Record` for dynamic/unknown key sets. * * @template T - Value type. Defaults to `unknown`. * * @example * const cache: DictionaryOpt = {}; * const hit = cache['key']; // number | undefined */ export type DictionaryOpt = {[key in string]?: T}; /** * A dense string-keyed map — every key is guaranteed to have a value. * Use when you control all keys and can assert their presence. * * @template T - Value type. Defaults to `unknown`. * * @example * const colors: DictionaryReq = { success: '#4CAF50' }; */ export type DictionaryReq = {[key: string]: T}; // ─── Object Utilities ──────────────────────────────────────────────────────── /** * Union of all required keys of `T`. * * @example * type Props = { a: number; b?: string }; * type R = RequiredKeys; // 'a' */ export type RequiredKeys = { [K in keyof T]-?: Record extends Pick ? never : K; }[keyof T]; /** * Union of all optional keys of `T`. * * @example * type Props = { a: number; b?: string }; * type O = OptionalKeys; // 'b' */ export type OptionalKeys = { [K in keyof T]-?: Record extends Pick ? K : never; }[keyof T]; /** * The type of property `K` in `T`, or `never` if `K` is not a key of `T`. * * @example * type User = { id: number; name: string }; * type NameType = Prop; // string */ export type Prop = K extends keyof T ? T[K] : never; /** * Union of all value types in object type `T`. * * @example * type Config = { host: string; port: number }; * type V = ObjectValues; // string | number */ export type ObjectValues = T[keyof T]; /** * Extracts the element type from an array or readonly array. * Returns `never` for non-array types. * * @example * type Users = { name: string }[]; * type User = ArrayItem; // { name: string } */ export type ArrayItem = T extends readonly (infer U)[] ? U : never; /** * Replaces properties of `M` with matching properties from `N`. * Properties in `N` that don't exist in `M` are added. * * @example * type A = { a: string; b: number }; * type B = { b: string; c: boolean }; * type C = Overwrite; // { a: string; b: string; c: boolean } */ export type Overwrite = Omit & N; /** * Eagerly evaluates a mapped or intersection type into a plain object shape. * Improves IDE tooltip readability for complex types. * * @example * type AB = Simplify<{ a: string } & { b: number }>; // { a: string; b: number } */ export type Simplify = {[K in keyof T]: T[K]} & NonNullable; /** * Structural interface for anything that exposes `addEventListener`. * Covers `EventTarget`, `HTMLElement`, `Window`, `Worker`, etc. */ export interface HasAddEventListener { addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: AddEventListenerOptions): void; } // ─── Deep Recursive ────────────────────────────────────────────────────────── /** * Built-in types whose internal structure should not be recursively transformed. * @internal */ type KeepMutable = | Date | RegExp | Promise | Map | Set | WeakMap | WeakSet; /** * Recursively makes every property of `T` (and nested objects/arrays) `readonly`. * Leaves primitives, functions, and `KeepMutable` types untouched. */ export type DeepReadonly = T extends Primitive | ((...args: any[]) => any) ? T : T extends KeepMutable ? T : T extends (infer U)[] ? readonly DeepReadonly[] : T extends readonly (infer U)[] ? readonly DeepReadonly[] : {readonly [P in keyof T]: DeepReadonly}; /** * Recursively makes every property of `T` required and strips `null | undefined` * from each value type. Leaves primitives, functions, and `KeepMutable` types untouched. */ export type DeepRequired = T extends Primitive | ((...args: any[]) => any) | KeepMutable ? T : T extends (infer U)[] ? DeepRequired>[] : T extends readonly (infer U)[] ? DeepRequired>[] : {[P in keyof T]-?: DeepRequired>}; /** * Recursively makes every property of `T` optional. * Leaves primitives, functions, and `KeepMutable` types untouched. */ export type DeepPartial = T extends Primitive | ((...args: any[]) => any) | KeepMutable ? T : T extends (infer U)[] ? DeepPartial[] : T extends readonly (infer U)[] ? DeepPartial[] : {[P in keyof T]?: DeepPartial}; // ─── JSON ───────────────────────────────────────────────────────────────────── /** A JSON-serialisable primitive value. */ export type JsonPrimitive = string | number | boolean | null | undefined; /** * Any JSON-serialisable value. * Recursive union of `JsonPrimitive`, `JsonObject`, and `JsonArray`. */ export type JsonValue = JsonPrimitive | JsonObject | JsonArray; /** A JSON-serialisable array. */ export type JsonArray = JsonValue[]; /** * A JSON-serialisable object. */ export interface JsonObject { [key: string]: JsonValue; } /** * Converts a TypeScript type `T` into its JSON-serialisable representation. * * Rules applied: * - Types with `toJSON()` resolve to its return type. * - `Date` → `string` (ISO 8601). * - `bigint`, functions, `undefined`, and `symbol` values are stripped. * - Objects and arrays are processed recursively. * * @example * type ApiResponse = { id: number; createdAt: Date; secret: symbol }; * type Wire = Jsonify; // { id: number; createdAt: string } */ export type Jsonify = T extends {toJSON(): infer J} ? J : T extends JsonPrimitive ? T : T extends bigint ? never : T extends Date ? string : T extends (infer U)[] ? Jsonify[] : T extends readonly (infer U)[] ? readonly Jsonify[] : T extends object ? {[K in keyof T as T[K] extends ((...args: any[]) => any) | undefined | symbol | bigint ? never : K]: Jsonify} : never;