The new operator is failing because it’s being used with a function that returns void, meaning it doesn’t produce a value that can be instantiated.
Common Causes and Fixes
-
Accidentally calling a
voidfunction withnew: This is the most straightforward cause. You might have a function that’s intended for side effects only, but you’re trying to create an instance of it.- Diagnosis: Look at the function signature. If it explicitly returns
voidor has no return type annotation (which defaults tovoidin TypeScript), this is your culprit.function doSomething(): void { console.log("Performing an action."); } - Fix: Remove the
newkeyword or change the function to return a value. IfdoSomethingis meant to be a constructor, it should returnthisor an instance of the class it belongs to.// Option 1: If it's not meant to be a constructor doSomething(); // Option 2: If it *is* meant to be a constructor (e.g., a class method) class MyClass { constructor() { console.log("Instance created."); } // ... other methods } const instance = new MyClass(); - Why it works: The
newoperator in JavaScript (and by extension, TypeScript) expects the constructor function to return an object. If it returnsundefined(which is what avoidfunction implicitly does), thenewoperator returns the newly created object (this) instead. However, TypeScript flags this at compile time because it’s usually a sign of a logical error.
- Diagnosis: Look at the function signature. If it explicitly returns
-
Misunderstanding Class vs. Function Constructors: You might be trying to use
newon a regular function that you intended to be a class constructor, but it’s missing the structure of a class or a factory function designed for instantiation.- Diagnosis: Check if the function in question is defined using the
classkeyword or if it’s a standalone function. If it’s a standalone function, examine its contents. Does it initialize properties onthis? Does it have a clear return value intended for instantiation?// Incorrect function OldStyleConstructor(name: string) { this.name = name; // No explicit return, defaults to undefined } // const person = new OldStyleConstructor("Alice"); // TS2350 error // Corrected (as a class) class Person { name: string; constructor(name: string) { this.name = name; } } const person = new Person("Alice"); - Fix: Convert the function into a
classor ensure the function is designed as a factory that returns an object. If it’s a legacy constructor function, ensure it implicitly returnsthisby not having an explicitreturnstatement that returns a non-object value.// For legacy functions that *should* work with new function LegacyConstructor(name: string) { this.name = name; // Implicitly returns 'this' } const legacyPerson = new LegacyConstructor("Bob"); - Why it works: Classes in JavaScript are syntactic sugar over constructor functions. When
newis used with a class, the JavaScript engine automatically handles the creation ofthisand its return. For older-style constructor functions, thenewoperator itself ensures thatthis(the newly created object) is returned, unless the function explicitly returns a different, non-primitive value.
- Diagnosis: Check if the function in question is defined using the
-
Incorrectly Typing a Constructor Function: You might have a function that is a constructor, but its type definition in TypeScript is incorrect, leading the compiler to believe it returns
void.- Diagnosis: Examine the type annotation for the function or the variable holding the constructor. It should be a
typeof ClassNameor a function type that expectsnew (...) => InstanceType.class MyService { constructor(private id: number) {} getId() { return this.id; } } // Incorrect typing const serviceConstructor: () => MyService = MyService; // TS2350 // const instance = new serviceConstructor(123); // Correct typing const correctServiceConstructor: new (id: number) => MyService = MyService; const instance = new correctServiceConstructor(123); - Fix: Ensure the type of the constructor variable correctly reflects its nature as a constructor. Use
new (...) => Typefor function types ortypeof ClassNamefor class types.const correctServiceConstructor: new (id: number) => MyService = MyService; - Why it works: The
new (...) => Typetype explicitly tells TypeScript that this function is intended to be called with thenewkeyword and will produce an instance ofType.typeof ClassNameis a shorthand for the constructor signature ofClassName.
- Diagnosis: Examine the type annotation for the function or the variable holding the constructor. It should be a
-
Using
newwith a Module or Namespace: Sometimes, people confuse modules or namespaces with classes or constructors. You cannot instantiate a module or a namespace withnew.- Diagnosis: Check if the identifier you’re using with
newrefers to a module (import ... from '...') or a namespace (namespace MyNamespace { ... }).// Example module // import * as fs from 'fs'; // const fileSystem = new fs(); // TS2350 error // Example namespace namespace Utils { export function format(s: string): string { return s.toUpperCase(); } } // const utilInstance = new Utils(); // TS2350 error - Fix: Remove the
newoperator. If you intended to use functions or classes within the module or namespace, import them directly or access them via their namespace.// For modules import * as fs from 'fs'; const fileContent = fs.readFileSync('path/to/file', 'utf-8'); // For namespaces const formattedString = Utils.format("hello"); - Why it works: Modules and namespaces are fundamentally different constructs from classes. They are used for organizing code and managing scope, not for creating individual instances of data structures.
- Diagnosis: Check if the identifier you’re using with
-
Library Functionality Misinterpretation: You might be using a library that exports functions or objects, and you’re mistakenly trying to instantiate one of them with
newwhen it’s designed to be called directly or is already an instance.- Diagnosis: Consult the library’s documentation. See how the specific function or object you’re trying to use is intended to be invoked. Look for examples of its usage.
// Hypothetical library usage import { createLogger } from 'some-logging-library'; // Incorrect: Assuming createLogger is a constructor // const logger = new createLogger({ level: 'info' }); // TS2350 error // Correct: Based on typical library patterns const logger = createLogger({ level: 'info' }); - Fix: Call the function or use the object as documented by the library. This usually means removing the
newkeyword.const logger = createLogger({ level: 'info' }); - Why it works: Libraries often provide factory functions (functions that create and return objects) or singleton instances. Using
newon a factory function that doesn’t expect it, or on a pre-existing object, will lead to type errors like TS2350 because these entities aren’t designed to be constructors.
- Diagnosis: Consult the library’s documentation. See how the specific function or object you’re trying to use is intended to be invoked. Look for examples of its usage.
-
Circular Dependencies with Constructors: In complex scenarios, circular dependencies involving class constructors can sometimes manifest in confusing ways. If Class A’s constructor somehow depends on an instance of Class B, and Class B’s constructor depends on an instance of Class A, and one of these dependencies is being incorrectly resolved or typed as
voidduring the instantiation chain, you might see this error.- Diagnosis: This is rare and harder to pinpoint. Use TypeScript’s
tsc --explainFilesand carefully trace the instantiation chain. Look forimplementsclauses or direct constructor arguments that might form a loop. - Fix: Refactor the code to break the circular dependency. This might involve using dependency injection, introducing a third mediating class, or re-architecting the relationship between the classes.
- Why it works: Breaking the cycle ensures that each constructor receives valid, fully initialized dependencies, preventing the
newoperator from encountering an unexpectedvoidreturn type in the chain.
- Diagnosis: This is rare and harder to pinpoint. Use TypeScript’s
After fixing TS2350, you might encounter TS2554: Expected N arguments, but got M if your constructor now correctly expects arguments that were previously not being passed due to the initial error.