This TypeScript error occurs when attempting to instantiate a type with the new operator that lacks a constructor signature. It commonly happens when trying to use interfaces, type aliases, or incorrectly imported types as constructors.
This error appears when TypeScript detects an attempt to use the `new` operator on a type that doesn't have a construct signature. In TypeScript, not all types can be instantiated - only classes and types with explicit constructor signatures can be used with `new`. The error most commonly occurs in scenarios like trying to instantiate an interface or type alias, using a type-only import as a constructor, or when there's a mismatch between how a module exports a class and how it's imported. TypeScript's type system distinguishes between the static side of a class (the constructor) and the instance side, and this error indicates that the type being used doesn't represent the constructor side. This can also occur with `esModuleInterop` settings when there's a mismatch between CommonJS and ES module exports, causing TypeScript to interpret a default export differently than expected.
Check your import statement to ensure you're importing the actual class or constructor, not a type definition.
Incorrect (type-only import):
import type { MyClass } from './my-class';
const instance = new MyClass(); // Error: not a constructorCorrect (value import):
import { MyClass } from './my-class';
const instance = new MyClass(); // WorksIf you're using import type, remove the type keyword or use a separate import for the value.
Interfaces and type aliases define shapes but cannot be instantiated. Replace them with classes if you need constructors.
Problem:
interface User {
name: string;
age: number;
}
const user = new User(); // Error: not a constructorSolution (use a class):
class User {
constructor(public name: string, public age: number) {}
}
const user = new User('Alice', 30); // WorksAlternatively, create an object literal or factory function instead of using new.
When using esModuleInterop, default exports may need different import syntax.
If you get this error with a library:
import * as EventEmitter from 'events';
const emitter = new EventEmitter(); // May failTry default import instead:
import EventEmitter from 'events';
const emitter = new EventEmitter(); // WorksOr check your tsconfig.json and ensure esModuleInterop is enabled:
{
"compilerOptions": {
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}If using a generic type parameter that should be constructable, add a constructor constraint.
Problem:
function create<T>(Type: T): T {
return new Type(); // Error: not a constructor
}Solution (add constructor constraint):
function create<T>(Type: new () => T): T {
return new Type(); // Works
}
// Or with parameters:
function createWith<T>(Type: new (name: string) => T, name: string): T {
return new Type(name);
}The new () => T syntax indicates that Type must be a constructor function.
If you're exporting both a type and a value with the same name, ensure imports are correct.
Export file (my-module.ts):
// Export the class (value)
export class Logger {
log(msg: string) { console.log(msg); }
}
// Export the type (if needed separately)
export type { Logger as LoggerType };Import file:
// Import the class value
import { Logger } from './my-module';
const logger = new Logger(); // Works
// Or import both
import { Logger, type LoggerType } from './my-module';If the error occurs only at runtime, check your TypeScript compilation target.
In tsconfig.json, ensure your target is appropriate:
{
"compilerOptions": {
"target": "ES2015", // or higher
"module": "commonjs"
}
}Some class features require ES2015 or higher. If targeting ES5, ensure your transpilation is handling classes correctly. You may also need to check if polyfills are required for your environment.
Constructor Signatures in Detail:
TypeScript distinguishes between the instance type of a class and its constructor type. The constructor type is represented using construct signatures: { new (...args): InstanceType }. This is particularly important when working with factory patterns or dependency injection.
esModuleInterop and Module Systems:
The esModuleInterop flag affects how TypeScript handles default exports from CommonJS modules. When enabled, it allows default imports from modules that don't explicitly have a default export, but this can sometimes cause type system confusion about what is and isn't a constructor. This is a common source of this error when migrating JavaScript codebases to TypeScript.
Abstract Classes:
Abstract classes cannot be instantiated directly but can be used in type positions that require constructor signatures if properly constrained:
abstract class Base {
abstract getValue(): number;
}
// This will error unless properly constrained
function factory<T extends Base>(Ctor: new () => T): T {
return new Ctor(); // T must be a concrete class, not abstract
}Type-Only Imports (TypeScript 3.8+):
The import type syntax was introduced to explicitly import only types, which are erased at runtime. This helps with tree-shaking but can cause this error if you accidentally use it for values you need to instantiate.
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