InstanceType<Type>

Extracts the instance type a constructor produces, usually written as InstanceType<typeof SomeClass>.

Signature
type InstanceType<Type extends abstract new (...args: any) => any> = Type extends abstract new (...args: any) => infer R ? R : any;
  • Added in TypeScript 2.8

Parameters

ParameterTypeDescription
$Typeabstract new (...args: any) => anyA constructor type. For a class declaration this is `typeof MyClass`, not `MyClass` — the latter is already the instance type.

Return value

R — the instance type produced by the constructorThe type of the object you get back from `new Type(...)`. `any` in, `any` out; `never` in, `never` out.

Errors

tsc errors when the argument does not satisfy `abstract new (...args: any) => any` — `InstanceType<string>` and `InstanceType<Function>` both fail and fall back to `any`.

Changelog

  • PHP 4.2The constraint became `abstract new (...args: any) => any`, so `InstanceType<typeof SomeAbstractClass>` resolves instead of erroring.

A class name in TypeScript means two different things. Used as a type, MyClass is the instance type. Used as a value, MyClass is the constructor, whose type is typeof MyClass. InstanceType converts the second back into the first.

You rarely need it for a concrete class — you would just write MyClass. It earns its place in generic code that receives a class as an argument: dependency-injection containers, plugin registries, test factories, anything with a signature like <C extends new (...args: any) => any>(ctor: C). Inside that function the return type has to be spelled InstanceType<C>, because C is the constructor and there is no other way to name what it builds.

What trips people up

  • Passing the class instead of typeof the class. InstanceType<MyClass> is an error; InstanceType<typeof MyClass> is what you want.
  • A private or protected constructor removes the public construct signature, so typeof MyClass no longer satisfies the constraint and the utility fails.
  • It reads only the construct signature. On an overloaded constructor you get the instance type of the last overload.

It pairs naturally with ConstructorParameters: one names the arguments in, the other names the object out, and together they type a fully generic factory.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Type the return value of a generic `create(ctor, ...args)` factory helper.
  • Declare a registry that maps class constructors to the singletons they produce.
  • Name the instance type of a class you only received as a `typeof` parameter in library code.

Frequently asked questions

What is the difference between MyClass and typeof MyClass?

`MyClass` is the instance type — the object a `new` call returns — while `typeof MyClass` is the constructor value's type, including static members. `InstanceType` maps the second back to the first, which is why you write `InstanceType<typeof MyClass>` and never `InstanceType<MyClass>`.

How do I type a factory function that takes any class?

Constrain the parameter with `C extends new (...args: any) => any`, spread `...args: ConstructorParameters<C>`, and return `InstanceType<C>`. The call site then infers the exact class you passed, so `build(Rect, 3, 4)` is typed `Rect` with no cast.

Why does InstanceType error on my class with a private constructor?

A private or protected constructor hides the public construct signature, so `typeof MyClass` no longer satisfies the `abstract new (...args: any) => any` constraint. Reference the class type directly (`MyClass`) or expose a static factory method instead.

More examples

A typed registry of services

`resolve` is generic over the constructor, so `resolve(Logger)` is typed as `Logger` and `resolve(Clock)` as `Clock` without any casts at the call site. The output shows the cached instance keeping its two log lines, the fixed clock value, and `true` — proof the same instance came back both times.

Example · typescript
class Logger {
  lines: string[] = [];
  log(msg: string) { this.lines.push(msg); return this; }
}

class Clock {
  fixed = "2024-01-01T00:00:00.000Z";
  now() { return this.fixed; }
}

const registry = new Map<Function, unknown>();

function resolve<C extends new () => any>(ctor: C): InstanceType<C> {
  if (!registry.has(ctor)) registry.set(ctor, new ctor());
  return registry.get(ctor) as InstanceType<C>;
}

resolve(Logger).log("boot").log("ready");
console.log(resolve(Logger).lines, resolve(Clock).now());
console.log(resolve(Logger) === resolve(Logger));

Instance types of abstract and edge-case constructors

`InstanceType<typeof Shape>` resolves to `Shape` even though the class is abstract and cannot be constructed — the utility describes the shape of the instance, it does not promise you can call `new`. The log prints `area=16`, since the value actually stored is a `Square`.

Example · typescript
abstract class Shape {
  abstract area(): number;
  describe() { return `area=${this.area()}`; }
}

class Square extends Shape {
  side = 4;
  area() { return this.side * this.side; }
}

// Since 4.2 the constraint allows abstract constructors:
type AnyShape = InstanceType<typeof Shape>;   // Shape
type AnySquare = InstanceType<typeof Square>; // Square

// Edge cases from the handbook:
type T1 = InstanceType<any>;   // any
type T2 = InstanceType<never>; // never

const s: AnyShape = new Square();
console.log(s.describe());

Discussion

  • Be the first to comment on this lesson.