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.
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
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");
}### 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;Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript