class
Constructor and instance type helpers.
import type {
Class, AbstractClass,
InstanceTypeSafe, ConstructorParametersSafe, IsClass,
} from '@gentleduck/ttest/class'
Constructor signatures expressed as type-level shapes. Use these to constrain dependency-injection containers, factory generics, or registries that hold class references. For plain functions see function.
Class
type Class<T = unknown, Args extends unknown[] = any[]> = new (...args: Args) => T
A concrete class constructor that produces instances of T. Args defaults to any[] so the helper is permissive about arity.
function inject<T>(Ctor: Class<T, [string]>, name: string): T {
return new Ctor(name)
}
class Service { constructor(public name: string) {} }
const s = inject(Service, 'analytics') // s: Service
// Constrain a registry to concrete classes only.
const registry: Record<string, Class<any>> = {
service: Service,
}
AbstractClass
type AbstractClass<T = unknown, Args extends unknown[] = any[]> = abstract new (...args: Args) => T
An abstract class constructor. Accepts both concrete and abstract classes — useful when you want to constrain a generic to "anything instanceof-checkable" without forbidding abstracts.
abstract class Base { abstract greet(): string }
class Hello extends Base { greet() { return 'hi' } }
function isInstanceOf<T>(value: unknown, Ctor: AbstractClass<T>): value is T {
return value instanceof Ctor
}
isInstanceOf(new Hello(), Base) // true
InstanceTypeSafe
type InstanceTypeSafe<C> = C extends new (...args: any[]) => infer T ? T : never
Instance type of constructor C, or never for non-constructors. Safer than the built-in InstanceType<T>, which errors on non-class input.
class User { constructor(public name: string) {} }
type a = InstanceTypeSafe<typeof User> // User
type b = InstanceTypeSafe<typeof Date> // Date
type c = InstanceTypeSafe<string> // never
ConstructorParametersSafe
type ConstructorParametersSafe<C> = C extends new (...args: infer P) => any ? P : never
Constructor parameter tuple, or never.
class User { constructor(public id: number, public name: string) {} }
type a = ConstructorParametersSafe<typeof User> // [id: number, name: string]
type b = ConstructorParametersSafe<typeof Date> // [] | [number] | [string] | ... (overloads collapse to last)
type c = ConstructorParametersSafe<() => void> // never
Edge case: like ParametersSafe, overloaded constructors collapse to the last overload — matches the built-in behavior.
IsClass
type IsClass<T> = T extends new (...args: any[]) => any ? true : false
true iff T is a constructor signature.
import type { AssertTrue, AssertFalse } from '@gentleduck/ttest/assert'
type _ = [
AssertTrue <IsClass<typeof Date>>,
AssertTrue <IsClass<typeof User>>,
AssertFalse<IsClass<() => void>>,
AssertFalse<IsClass<{ kind: 'data' }>>,
]
Edge case: arrow functions and plain functions are not constructors — IsClass<() => void> is false. Use IsFunction or ReturnTypeSafe for those.