How to fix Cannot use 'new' with an expression whose type lacks a construct signature in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 8, 2025· 132 views

This error occurs when you attempt to use the 'new' keyword with a value that TypeScript doesn't recognize as constructable (doesn't have a construct signature). The fix involves either converting constructor functions to classes, properly typing the constructor, or using type assertions.

Quick fix

Fixes TS2351

function Employee(fullName: string, salary: number) {
  this.fullName = fullName;
  this.salary = salary;
}

// TS2351 Error here:
const emp1 = new Employee('Bobby Hadz', 100);
  1. Convert constructor function to a class
  2. Type the 'this' parameter in constructor functions
  3. Remove the 'new' keyword if not needed
  4. Add construct signature to function type
typescript — error
function Employee(fullName: string, salary: number) {
this.fullName = fullName;
this.salary = salary;
}
// TS2351 Error here:
const emp1 = new Employee('Bobby Hadz', 100);
Cannot use 'new' with an expression whose type lacks a construct signature

What this error means

This TypeScript error indicates you're trying to instantiate something with the 'new' keyword, but TypeScript's type system doesn't recognize it as a constructor. In TypeScript, a "construct signature" is the type definition that tells TypeScript "this thing can be instantiated with the new keyword." Classes have construct signatures by default, but plain functions, interfaces, and other types often don't unless explicitly defined. Common scenarios that trigger this error: 1. Trying to use 'new' with a regular function instead of a class 2. Using 'new' with an imported value that's not properly typed as a constructor 3. Attempting to instantiate a type or interface directly 4. Dynamic imports or values that lose type information TypeScript's recommendation is to convert constructor functions to proper classes, as they provide better type safety and clearer intent.

Typical symptoms

  • TypeScript compiler shows error TS2351 or TS2302
  • 'new' keyword is underlined with a red squiggle in your editor
  • The value you're trying to instantiate is highlighted as problematic
  • Error appears when refactoring legacy JavaScript to TypeScript
  • Works at runtime but TypeScript compilation fails
  • Issue occurs after upgrading TypeScript to a stricter version
  • Error happens with dynamically imported or conditionally loaded modules
  • Type checking works for some calls to 'new' but not others

Common causes

  1. Using 'new' with a regular function instead of a class
  2. Function parameter or variable lacks explicit constructor type definition
  3. Imported value is not properly typed as a constructor
  4. Type is defined as an interface instead of a class
  5. Using 'new' with a type assertion that doesn't represent a constructor
  6. Constructor function's 'this' parameter is not properly typed
  7. Generic type or type variable doesn't have a constructor constraint
  8. Legacy JavaScript value imported without proper TypeScript type definitions

How to fix "Cannot use 'new' with an expression whose type lacks a construct signature"

1Convert constructor function to a class

The simplest and most recommended solution is to convert your constructor function to a TypeScript class:

Before (causes TS2351):

typescript
function Employee(fullName: string, salary: number) {
  this.fullName = fullName;
  this.salary = salary;
}

// TS2351 Error here:
const emp1 = new Employee('Bobby Hadz', 100);

After (no error):

typescript
class Employee {
  constructor(
    public fullName: string,
    public salary: number,
  ) {}

  getSalary() {
    return this.salary;
  }
}

// Works correctly:
const emp1 = new Employee('Bobby Hadz', 100);

Classes are TypeScript's preferred way to define constructors because they:
- Have explicit construct signatures
- Support inheritance clearly
- Work with access modifiers (public, private, protected)
- Are well understood by type checkers

2Type the 'this' parameter in constructor functions

If you must use a constructor function (not recommended), explicitly type the 'this' parameter:

With typed 'this':

typescript
function Employee(this: any, fullName: string, salary: number) {
  this.fullName = fullName;
  this.salary = salary;
  this.getSalary = function () {
    return this.salary;
  };
}

// Still requires type assertion:
const emp1 = new (Employee as any)('Bobby Hadz', 100);

This tells TypeScript that 'this' will be an object where you can set properties. However, you still need to use a type assertion (as any) with the 'new' keyword because constructor functions alone don't have construct signatures.

Better approach - use a constructor interface:

typescript
interface EmployeeConstructor {
  new (fullName: string, salary: number): Employee;
}

interface Employee {
  fullName: string;
  salary: number;
  getSalary(): number;
}

function Employee(this: Employee, fullName: string, salary: number) {
  this.fullName = fullName;
  this.salary = salary;
}

Employee.prototype.getSalary = function () {
  return this.salary;
};

// Type the variable as the constructor interface:
const EmployeeConstructor: EmployeeConstructor = Employee as any;
const emp1 = new EmployeeConstructor('Bobby Hadz', 100);
3Remove the 'new' keyword if not needed

Sometimes the error occurs because you're using 'new' unnecessarily. Check if the value is actually a constructor:

Example - NextResponse.json() is a static method:

typescript
// Wrong - NextResponse.json() is not a constructor:
return new NextResponse.json({ message: 'Hello' });

// Correct - call it as a regular function:
return NextResponse.json({ message: 'Hello' });

Common cases where 'new' is unnecessary:
- Static factory methods: new Class.create() → Class.create()
- Utility functions: new getConfig() → getConfig()
- Module exports that are functions: new myFunction() → myFunction()

Check the library documentation to verify if something should be instantiated with 'new' or called directly.

4Add construct signature to function type

If you're working with a function type that needs to be constructable, add a construct signature:

For function types:

typescript
// Define what 'new' should do with this function
type Constructor = new (name: string) => { name: string };

// This function matches the Constructor type:
function MyClass(this: { name: string }, name: string) {
  this.name = name;
}

// Use with proper typing:
const MyClassConstructor: Constructor = MyClass as any;
const instance = new MyClassConstructor('test');

For class-like objects:

typescript
// Define both static and instance types
interface MyClassStatic {
  new (): MyClassInstance;
}

interface MyClassInstance {
  method(): void;
}

// Declare the variable with the static interface:
declare const MyClass: MyClassStatic;
const instance = new MyClass();
5Use type assertion with 'as' for dynamic values

When dealing with dynamically imported or computed values, use type assertions:

For dynamically loaded classes:

typescript
async function loadPlugin(pluginName: string) {
  const module = await import(`./plugins/${pluginName}`);

  // Type assert as a constructor
  type AnyConstructor = new (...args: any[]) => any;
  const PluginClass = module.default as AnyConstructor;

  // Now 'new' works without error:
  const instance = new PluginClass();
  return instance;
}

For values from external libraries:

typescript
import { someValue } from 'some-library';

// If someValue should be constructable, assert it:
type Constructable<T> = new (...args: any[]) => T;
const Constructor = someValue as Constructable<MyType>;

const instance = new Constructor();

Be cautious with type assertions - they tell TypeScript to trust your typing. Use only when you're certain about the actual runtime type.

6Check imported type definitions

If the error occurs with an imported library, verify the types are correct:

Check if types are installed:

bash
# For popular libraries, @types packages provide TypeScript definitions
npm install --save-dev @types/some-library

Verify the import is correct:

typescript
// Wrong - importing the namespace instead of the class:
import * as MyClass from './MyClass';
const instance = new MyClass(); // Error

// Correct - import the class directly:
import MyClass from './MyClass';
const instance = new MyClass(); // OK

Check type definition file:

typescript
// Look at the .d.ts file or source to verify it exports a class/constructor
// For example, in node_modules/@types/some-lib/index.d.ts:

// If it's exported as class:
export class SomeClass { }

// If it's exported as namespace:
export namespace SomeClass { }

// The second case won't work with 'new'
7Enable strict TypeScript settings for better error catching

Update your tsconfig.json to catch these issues earlier:

json
{
  "compilerOptions": {
    // Enable strict mode for better type safety
    "strict": true,

    // More granular strict options:
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitAny": true,
    "noImplicitThis": true,

    // Helps catch constructor issues:
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,

    // Module resolution:
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

With strict mode enabled, TypeScript will catch missing constructor signatures earlier in development rather than at runtime.

Advanced notes

### Understanding Construct Signatures

A construct signature tells TypeScript that something can be instantiated with 'new'. In the type system, it looks like:

typescript
// Construct signature in an interface
interface Constructor {
  new (arg: string): Instance;
}

// This is different from a regular function signature
interface CallableFunction {
  (arg: string): Instance;
}

Classes automatically have construct signatures for their constructors. Regular functions don't unless you explicitly define them.

### Generic Constructor Constraints

When working with generics, ensure the type parameter is constrained to be constructable:

typescript
// Without constraint - doesn't work with 'new':
function create<T>(TypeClass: T): T {
  return new TypeClass(); // Error
}

// With constructor constraint - works correctly:
function create<T>(TypeClass: new () => T): T {
  return new TypeClass();
}

// Usage:
class MyClass {
  name = 'test';
}

const instance = create(MyClass); // OK

### Factory Pattern as Alternative

If constructors are causing type issues, consider the factory pattern:

typescript
// Instead of class with problematic constructor:
class Config {
  private constructor(private data: any) {}

  // Factory method instead:
  static create(data: any): Config {
    return new Config(data);
  }
}

// Usage is cleaner and types better:
const config = Config.create({ ... });

### NextResponse and Framework-Specific Examples

In Next.js, many utilities are factory functions, not constructors:

typescript
// NextResponse is a factory function, not a constructor:
import { NextResponse } from 'next/server';

// WRONG:
new NextResponse.json({ message: 'OK' }); // Error

// CORRECT:
NextResponse.json({ message: 'OK' });
NextResponse.next();
NextResponse.redirect('/path');

### Debugging Type Issues

If you're unsure whether something is constructable, check at the source:

typescript
// TypeScript can show you the type:
import SomeValue from 'some-lib';

// Hover over SomeValue in VS Code to see its type
// Or use this to force an error that shows the type:
type Check = typeof SomeValue;

// Check if it's callable vs constructable:
const test1: typeof SomeValue = (arg) => {}; // If assignable, it's callable
const test2: new () => any = SomeValue; // If assignable, it's constructable

### Common Library Patterns

Different libraries use different patterns:

Classes (constructable):

typescript
import * as path from 'path'; // No - just utilities
import express from 'express'; // No - it's a factory function
const app = express(); // Call it

class MyClass { } // Yes - constructable
const instance = new MyClass();

Factory patterns (not constructable):

typescript
// Stripe SDK uses functions, not classes:
const stripe = require('stripe')(apiKey);
// Not: new require('stripe')(apiKey)

// React uses both functions and classes:
const element = React.createElement(...); // Factory
class MyComponent extends React.Component {} // Class

### TypeScript Error Messages

Error TS2351 appears in different contexts:

- "Cannot use 'new' with an expression whose type lacks a construct signature" - main error
- "Cannot find name 'SomeValue'" - type not found
- "Type 'X' is not constructable" - similar error with different wording

All indicate the same issue: trying to use 'new' with something TypeScript doesn't recognize as a constructor.

Frequently asked questions

What does "TS2351" mean?
This TypeScript error indicates you're trying to instantiate something with the 'new' keyword, but TypeScript's type system doesn't recognize it as a constructor. " Classes have construct signatures by default, but plain functions, interfaces, and other types often don't unless explicitly defined. Common scenarios that trigger this error: 1.
How do I fix "TS2351"?
This error occurs when you attempt to use the 'new' keyword with a value that TypeScript doesn't recognize as constructable (doesn't have a construct signature). The fix involves either converting constructor functions to classes, properly typing the constructor, or using type assertions.
What causes "TS2351"?
Using 'new' with a regular function instead of a class Function parameter or variable lacks explicit constructor type definition Imported value is not properly typed as a constructor
Is the "TS2351" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading