InstanceType<Type>
Extracts the instance type a constructor produces, usually written as InstanceType<typeof SomeClass>.
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
| Parameter | Type | Description |
|---|---|---|
$Type | abstract new (...args: any) => any | A 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
typeofthe 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 MyClassno 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
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.
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`.
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