Function and Functional
The function category identifies and manipulates function types.
The functional category provides runtime helpers written in a functional style, plus the types that describe them.
The class category, covered at the end, handles the constructor side of the same thing.
IsFunction and IsNotFunction
Section titled “IsFunction and IsNotFunction”type IsFunction<T, $O extends IsFunction.$Options = {}>type IsNotFunction<T, $O extends IsNotFunction.$Options = {}>🎭 predicate — validates that T is Function or any function signature.
import type { IsFunction, IsNotFunction } from 'type-plus'
type R = IsFunction<Function> // truetype R = IsFunction<() => void> // true
type R = IsFunction<number> // falsetype R = IsFunction<never> // falsetype R = IsFunction<unknown> // false
type R = IsNotFunction<() => void> // falsetype R = IsNotFunction<number> // trueBoth are distributive, so a union that mixes functions and non-functions yields boolean:
type R = IsFunction<Function | number> // booleantype R = IsFunction<Function | number, { distributive: false }> // falseWith selection: 'filter' they become filters instead of predicates:
type R = IsFunction<(() => string) | number, { selection: 'filter' }> // () => stringtype R = IsNotFunction<(() => string) | number, { selection: 'filter' }> // numberThey support the full option set — $any, $unknown, $never, $void, $then, $else,
selection, distributive, and the $Branch selectors. See type branching
and options.
IsStrictFunction and IsNotStrictFunction
Section titled “IsStrictFunction and IsNotStrictFunction”type IsStrictFunction<T, $O extends IsStrictFunction.$Options = {}>type IsNotStrictFunction<T, $O extends IsNotStrictFunction.$Options = {}>🎭 predicate — validates that T is exactly Function, not a specific call signature.
import type { IsStrictFunction, IsNotStrictFunction } from 'type-plus'
type R = IsStrictFunction<Function> // truetype R = IsStrictFunction<() => void> // falsetype R = IsStrictFunction<(() => void) & { a: 1 }> // false
type R = IsNotStrictFunction<Function> // falsetype R = IsNotStrictFunction<() => void> // trueUse these when the distinction between the bare Function type and a callable signature matters.
They take the same options as IsFunction.
AnyFunction
Section titled “AnyFunction”type AnyFunction<Params extends any[] = any[], Result = any> = (...args: Params) => Result🧰 type util — a constraint for “any function”, with optional parameter and result types.
import type { AnyFunction } from 'type-plus'
function callTwice<F extends AnyFunction>(fn: F) { /* ... */}
type Handler = AnyFunction<[event: string], void> // (event: string) => voidExtractFunction
Section titled “ExtractFunction”type ExtractFunction<T extends AnyFunction>function extractFunction<T extends AnyFunction>(fn: T): ExtractFunction<T>⚗️ transform — pulls the call signature out of a composite type, dropping the extra properties.
import { extractFunction, type ExtractFunction } from 'type-plus'
type Composite = (() => void) & { a: 1 }
type R = ExtractFunction<Composite> // () => void
const fn = extractFunction((() => {}) as Composite) // () => voidIt works on an intersection of a function with other members. It does not work on overloads or unions.
ChainFn and EndoFn
Section titled “ChainFn and EndoFn”type ChainFn<T> = (param: T) => Ttype EndoFn<T> = (param: T) => TBoth describe a function that returns the same type it takes.
ChainFn names the chaining use case; EndoFn names the mathematical one — an endofunctor maps a category back to itself.
import type { ChainFn } from 'type-plus'
const trim: ChainFn<string> = (s) => s.trim()compose
Section titled “compose”function compose<FS extends AnyFunction[]>( ...fns: FS): (...args: Parameters<Head<FS>>) => ReturnType<Last<FS>>Composes functions left to right. Each function receives the previous function’s return value. The composed function takes the parameters of the first function and returns the result of the last.
import { compose } from 'type-plus'
const parseThenDouble = compose( (s: string) => Number.parseInt(s, 10), (n: number) => n * 2,)
parseThenDouble('21') // 42, typed (s: string) => numbercontext
Section titled “context”function context<Init extends ContextBaseShape, Ctx extends ContextBaseShape = Init>( init?: Init | (() => Init),): ContextBuilder<Init, Ctx>Builds a context object incrementally. Each extend() adds properties and widens the resulting type;
build() produces the accumulated context.
import { context } from 'type-plus'
const ctx = context({ id: 1 }) .extend((c) => ({ label: `item-${c.id}` })) .extend(() => ({ enabled: true })) .build() // { id: number; label: string; enabled: boolean }An extender returns only the new properties; the builder left-joins them onto the current context. Returning an existing property overrides its value.
Supporting types:
| Type | Description |
|---|---|
ContextBaseShape |
Record<string | symbol, any> — the constraint every context satisfies. |
ContextExtender<Current, Additional> |
(context: Current) => Additional — the shape of an extend() callback. |
ContextBuilder<Init, Ctx> |
The builder returned by context(), exposing extend() and build(). |
Classes
Section titled “Classes”A class is a function with a new signature, so the class category lives here.
AnyConstructor
Section titled “AnyConstructor”type AnyConstructor<Params extends any[] = any[]> = new (..._args: Params) => void🧰 type util — the AnyFunction of classes: a constraint for “any class”.
import type { AnyConstructor } from 'type-plus'
class Foo { constructor(_a: number) {}}
type R = typeof Foo extends AnyConstructor ? true : false // truetype R = Foo extends AnyConstructor ? true : false // false, `Foo` is the instance typetype R = typeof Foo extends AnyConstructor<[string]> ? true : false // falseThe return type is void, not the instance type. That is what lets it match every class regardless of
what it constructs. Use typeof TheClass, not TheClass: the bare name is the instance type.
isInstanceof
Section titled “isInstanceof”function isInstanceof<T extends AnyConstructor>( subject: unknown, classConstructor: T,): subject is InstanceType<T>🛡️ type guard — instanceof for a value typed unknown, narrowing it to the instance type.
import { isInstanceof } from 'type-plus'
function handle(err: unknown) { if (isInstanceof(err, TypeError)) { err.message // narrowed to TypeError }}Plain instanceof already narrows a typed value. This is for the unknown case, where writing the
predicate by hand means repeating the instance type.
isConstructor
Section titled “isConstructor”function isConstructor(subject: unknown): subject is AnyConstructor💀 deprecated — no replacement.
It calls new on the subject and reads the error message to decide, so it returns true for any function
that can be called with new, and an arrow function can still pass after compilation. There is no
reliable runtime test for this; check for what you actually need instead.