How to fix Constructor of class 'X' is not compatible with constructor signature of type 'Y' in TypeScript
This error occurs when a class's constructor signature doesn't match the constructor signature expected by a type or interface. TypeScript is strict about constructor compatibility when using classes with type-based constructor signatures.
Quick fix
Fixes TS2322
// If you see this error:
// Type 'MyClass' is not assignable to type 'ConstructorType'
// Constructor of class 'MyClass' is not compatible with
// constructor signature of type 'ConstructorType'
type ConstructorType = new (x: string, y: number) => any;
class MyClass {
constructor(x: number) {
// Parameter order/types don't match
}
}
const ctor: ConstructorType = MyClass; // ERROR- Understand the type being assigned
- Fix the class constructor parameters
- Handle optional/variadic parameters correctly
- Use the constructor type pattern for factories
// If you see this error:// Type 'MyClass' is not assignable to type 'ConstructorType'// Constructor of class 'MyClass' is not compatible with// constructor signature of type 'ConstructorType'type ConstructorType = new (x: string, y: number) => any;class MyClass {constructor(x: number) {// Parameter order/types don't match}}const ctor: ConstructorType = MyClass; // ERRORConstructor of class 'X' is not compatible with constructor signature of type 'Y'
What this error means
TypeScript has a unique constraint: classes have both an instance side and a static side. The instance side contains instance properties and methods, while the static side contains the constructor. When you define an interface with a constructor signature (using the `new` keyword) and try to use a class to satisfy that interface, TypeScript checks whether the class constructor matches. Similarly, if you assign a class to a variable that expects a specific constructor signature, TypeScript enforces compatibility. The key issue is that when you `implements` an interface, TypeScript only checks the instance side of the class, not the constructor. This is why you can have a class that implements an interface but still fail the constructor signature check. This error typically appears when: - A class is assigned to a type that expects a different constructor signature - A class constructor has different parameter types, order, or optionality than expected - You're using the class as a factory function in code that expects a specific constructor shape
Typical symptoms
- TypeScript compiler error when assigning a class to a variable with a constructor type
- Error appears when passing a class as an argument to a function expecting a constructor type
- Works fine with class instances but fails when referencing the class constructor itself
- Removing specific parameters from the constructor causes the error to disappear
- Adding optional parameters or changing parameter types changes the error
- Using `implements` on an interface with constructor signatures fails compilation
Common causes
- Class constructor parameters don't match the expected type signature (most common)
- Parameter order is different between the class and the expected type
- Parameter types differ (e.g., string vs number)
- One constructor has optional parameters while the other doesn't
- Using class instantiation in a context that expects a constructor type reference
- Trying to implement an interface that includes a constructor signature
- Variance mismatch with constructor parameter types (contravariance rules apply)
How to fix "Constructor of class 'X' is not compatible with constructor signature of type 'Y'"
First, identify what type signature the class needs to match. Look at the error message carefully:
// If you see this error:
// Type 'MyClass' is not assignable to type 'ConstructorType'
// Constructor of class 'MyClass' is not compatible with
// constructor signature of type 'ConstructorType'
type ConstructorType = new (x: string, y: number) => any;
class MyClass {
constructor(x: number) {
// Parameter order/types don't match
}
}
const ctor: ConstructorType = MyClass; // ERRORThe error tells you exactly what the expected constructor signature is.
Modify the class constructor to match the expected parameter types and order:
type ConstructorType = new (x: string, y: number) => any;
class MyClass {
constructor(x: string, y: number) {
// Now matches the expected signature
}
}
const ctor: ConstructorType = MyClass; // OKMake sure:
- Parameter names match (TypeScript checks this)
- Parameter types match exactly
- Parameter order matches
- Optional parameters are in the right places
If the expected constructor has optional parameters, match that in your class:
// Expected: optional parameter
type ConstructorType = new (x?: string) => any;
class MyClass {
constructor(x?: string) {
// Correctly matches optional parameter
}
}
const ctor: ConstructorType = MyClass; // OK
// For rest parameters:
type VarConstructor = new (...args: any[]) => any;
class VarClass {
constructor(...args: any[]) {
// Correctly matches variadic parameters
}
}
const varCtor: VarConstructor = VarClass; // OKIf you're trying to create a factory pattern, split the interface into constructor and instance types:
// WRONG: Trying to implement constructor signature directly
interface ClockConstructor {
new (hour: number, minute: number): Clock;
}
// Can't do this - class implements only the instance side
class Clock implements ClockConstructor {
constructor(h: number, m: number) {}
tick() {}
}
// RIGHT: Create separate types
interface Clock {
tick(): void;
hour: number;
minute: number;
}
interface ClockConstructor {
new (hour: number, minute: number): Clock;
}
class Clock implements Clock {
hour: number;
minute: number;
constructor(h: number, m: number) {
this.hour = h;
this.minute = m;
}
tick() {
this.minute++;
}
}
// Now you can use Clock as a constructor
const ctor: ClockConstructor = Clock; // OKRemember that constructor parameters are contravariant. A constructor accepting a broader type can't be used where a stricter type is expected:
type ConstructorType = new (x: string | number) => any;
class MyClass {
// WRONG: Requires a string, but constructor type accepts string | number
constructor(x: string) {
// Parameter type is too strict
}
}
const ctor: ConstructorType = MyClass; // ERROR
// CORRECT: Accept the same or broader type
class MyClass {
constructor(x: string | number | boolean) {
// Parameter type is equal to or broader
}
}
const ctor: ConstructorType = MyClass; // OKAfter fixing the constructor signature, verify your class works as expected:
type ConstructorType = new (x: string) => { getValue(): string };
class MyClass {
private value: string;
constructor(x: string) {
this.value = x;
}
getValue() {
return this.value;
}
}
// Use the constructor
const ctor: ConstructorType = MyClass;
const instance = new ctor("hello");
console.log(instance.getValue()); // "hello"
// Verify the instance
if (instance instanceof MyClass) {
console.log("Instance created successfully");
}Advanced notes
### Mixin Patterns and Constructor Constraints
When using mixin patterns, the type parameter must be constrained to a mixin constructor type:
type Constructor = new (...args: any[]) => {};
function Timestamped<T extends Constructor>(Base: T) {
return class extends Base {
timestamp = Date.now();
};
}
// Works: constructor accepts any arguments
class User {
constructor(name: string) {}
}
const TimestampedUser = Timestamped(User); // OK### Constructor Return Type Mismatch
The error TS2203 (Construct signature return types differ) occurs when constructors return different types:
type ConstructorA = new () => { x: number };
type ConstructorB = new () => { x: string };
// Can't assign ConstructorB to ConstructorA
// because return types don't match### Static vs Instance Side
Remember that implements checks only the instance side:
interface MyInterface {
instanceMethod(): void;
}
interface MyStaticInterface {
new (): MyInterface;
staticMethod(): void;
}
class MyClass implements MyInterface {
instanceMethod() {}
static staticMethod() {}
}
// This checks only instance side (OK)
const instance: MyInterface = new MyClass();
// This checks constructor and static side (may fail)
const ctor: MyStaticInterface = MyClass as any;Frequently asked questions
- What does "TS2322" mean?
- TypeScript has a unique constraint: classes have both an instance side and a static side. The instance side contains instance properties and methods, while the static side contains the constructor. When you define an interface with a constructor signature (using the new keyword) and try to use a class to satisfy that interface, TypeScript checks whether the class constructor matches.
- How do I fix "TS2322"?
- This error occurs when a class's constructor signature doesn't match the constructor signature expected by a type or interface. TypeScript is strict about constructor compatibility when using classes with type-based constructor signatures.
- What causes "TS2322"?
- Class constructor parameters don't match the expected type signature (most common) Parameter order is different between the class and the expected type Parameter types differ (e.g., string vs number)
- Is the "TS2322" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- ๐TypeScript Official Documentation
- ๐TypeScript Handbook - Classes(Official Docs)
- ๐TypeScript Handbook - Interfaces(Official Docs)
- ๐TypeScript Handbook - Type Compatibility(Official Docs)
- ๐
- ๐