Skip to content
TypeScript ts utility-types 3 min read

ConstructorParameters & InstanceType

ConstructorParameters<T> and InstanceType<T> are the class-oriented counterparts to Parameters and ReturnType. Given a constructor type — typically typeof SomeClass — they extract the tuple of arguments new expects and the type of the object it produces. They are invaluable for writing factories, dependency-injection containers, and generic wrappers that must operate over arbitrary classes without hard-coding each one. Like their function cousins, both are tiny conditional types using infer. This page covers usage, implementation, and how they combine.

ConstructorParameters: the new() argument tuple

ConstructorParameters<T> returns a tuple of the types the constructor accepts. Pass the class value through typeof to get its constructor type.

class HttpClient {
  constructor(baseUrl: string, timeout: number, retries = 0) {}
}

type Args = ConstructorParameters<typeof HttpClient>;
// [baseUrl: string, timeout: number, retries?: number]

const args: Args = ["https://api.dev", 5000];
const client = new HttpClient(...args); // ✅

The tuple preserves labels and optionality exactly like Parameters. Spreading it into new HttpClient(...args) is fully type-checked, so missing or extra arguments are rejected.

InstanceType: the produced object type

InstanceType<T> yields the type of an instance the constructor creates — equivalent to the class name used as a type, but derived from the constructor value.

class Repository<T> {
  items: T[] = [];
  add(item: T) {
    this.items.push(item);
  }
}

type Repo = InstanceType<typeof Repository>;
// Repository<unknown>

function makeRepo<C extends new (...a: any[]) => any>(Ctor: C): InstanceType<C> {
  return new Ctor();
}

This matters in generic code where you only have the constructor as a value (C) and need to name the type of what new Ctor() returns — there is no Ctor type to reference directly.

How they are implemented

Both are conditional types constrained to abstract new (...args: any) => any, so they also accept abstract class constructors.

type MyConstructorParameters<T extends abstract new (...a: any) => any> =
  T extends abstract new (...args: infer P) => any ? P : never;

type MyInstanceType<T extends abstract new (...a: any) => any> =
  T extends abstract new (...args: any) => infer R ? R : any;

infer P captures the constructor’s parameter list as a tuple; infer R captures the instance type. The abstract modifier in the constraint lets these work on classes you cannot instantiate directly.

A type-safe generic factory

Combining both utilities lets you write one factory that constructs any class while keeping argument and result types correct.

function create<C extends new (...args: any[]) => any>(
  Ctor: C,
  ...args: ConstructorParameters<C>
): InstanceType<C> {
  return new Ctor(...args);
}

const c = create(HttpClient, "https://api.dev", 5000);
// c: HttpClient ✅

create(HttpClient, "https://api.dev"); // ❌ Error: missing 'timeout'

The ...args: ConstructorParameters<C> ties the factory’s rest arguments to the class’s real constructor, and the InstanceType<C> return type means c is correctly typed as an HttpClient with no casting.

Comparison

UtilityInputOutput
ConstructorParameters<T>typeof Classtuple of new arguments
InstanceType<T>typeof Classtype of new Class()
Parameters<T>function typetuple of call arguments
ReturnType<T>function typereturn type

Pass typeof MyClass (the constructor), not MyClass (the instance type). Feeding the instance type fails the new (...) => any constraint and produces an error.

Best Practices

  • Always pass typeof Class; these utilities operate on the constructor, not the instance type.
  • Use InstanceType<C> to name a generic class’s instance when you only hold the constructor value.
  • Combine both in factory helpers so argument lists and return types track the class automatically.
  • Remember the constraint allows abstract constructors, so abstract classes work as inputs.
  • Prefer deriving from a single class over maintaining a parallel hand-written constructor signature.
  • Reach for Parameters/ReturnType for plain functions and these two for classes.
  • Spread ConstructorParameters<C> into new Ctor(...) to keep instantiation fully checked.
Last updated June 29, 2026
Was this helpful?