What is the process of converting the new syntax of SomeFunction() to TypeScript?

When I try to convert a basic JS file to TS while having implicit "any" disabled, I encounter the following error:

Error TS7009: When attempting to create a new expression without a constructor signature, it implicitly defaults to an 'any' type.

interface Logger {
    new (): any;
}

interface LoggerInstance {
}

function Logger(): void {
}


var defaultLogger: LoggerInstance = new Logger();//error TS7009

I'm stuck on how to resolve this issue without turning the Logger function into a class.

The TypeScript compiler was providing suggestions for improvement when implicit any wasn't disabled, so I prefer to keep that setting enabled.

Update: After removing "new" from the Logger interface and casting the result of new Logger(...) in the full file, I managed to compile it. However, I still face the same error in my smaller test case.

Update 2: It seems that the error warnings disappear when the plugin highlighting syntax errors crashes. It appears that this method of object creation may not be allowed when "implicit any" is turned off.

Answer №1

A quick solution

interface IPerson {
    name: string;
}

var person = function(name: string) : void {
    this.name = name;
}

let funcPerson = <IPerson>(new (<any>(person("John Doe"))));

This code works fine with the noImplicitAny flag enabled.

An improved approach

You can simply convert the function into a class:

class person {
    constructor(public name: string) { }
}

let classPerson = person("John Doe");

After compilation, this becomes:

var person = (function () {
    function person(name) {
        this.name = name;
    }
    return person;
})();
var classPerson = new person("Jane Doe");

Converting the function to a class is beneficial for readability, refactoring, and future modifications. It provides better type information and eliminates the need for an interface in this case.

In summary, there is little reason to prefer the function version over the class implementation. Both yield equivalent objects (see classPerson and funcPerson).

Another alternative

If you want to use a working .js file with TypeScript, consider creating a .d.ts file like this:

person.js

var person = function(name) {
    this.name = name;
}

person.d.ts

interface PersonStatic {
    name:string;
    new(name: string) : PersonStatic;
}
declare var person: PersonStatic;

With this setup, you can do:

/// <reference path="your.d.ts"/>
var p = new person("Jane Doe");

Ensure that the person.js file is available at runtime for proper execution. The example .d.ts file provided is basic; if you pursue this option, it's recommended to learn more about creating .d.ts files beforehand.

Answer №2

Explain the structures of type and its constructor. Utilizing interfaces would be an ideal approach.

type PersonType = {
    name: string;
    greet: (otherPerson: PersonType) => string;
    selfIntroduce: () => string;
}

//When it comes to ordinary functions, they can be called with or without the "new" operator and
//the type of the constructor must specify both signatures

type PersonTypeConstructor = {
    (this: PersonType, name: string): void; //<- The use of "this" here is optional
    new(name: string): PersonType; // <- Do not include "this" here
}

Create the function meant for serving as the constructor. It is crucial to specify this as the initial parameter(since TS 2.0) in order to prevent compiler errors when the noImplicitThis flag is enabled.

const Person = (function Person(this: PersonType, name: string) { 
    this.name = name;
}) as PersonTypeConstructor; // <- This casts the constructor making further casting unnecessary.

Person.prototype.greet = function (otherPerson: PersonType) {
    return `Hello, ${otherPerson.name}!`;
};

Person.prototype.selfIntroduce = function () {
    return `Hello, my name is ${this.name}.`;
};

let peggySue = new Person("Peggy Sue");
let maryAnn  = new Person("Mary Ann");

console.log(maryAnn.selfIntroduce());
console.log(peggySue.greet(maryAnn));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular 6: Issue TS2339 - The attribute 'value' is not recognized on the 'HTMLElement' type

I have a textarea on my website that allows users to submit comments. I want to automatically capture the date and time when the comment is submitted, and then save it in a JSON format along with the added comment: After a comment is submitted, I would li ...

The Angular application is receiving a 404 error when trying to access the .NET Core

Having trouble calling a method in the controller via URL, as I keep encountering a 404 error. What could be the issue? API Endpoint: http://localhost:5000/Home/HomeTest /*.net core web-api*/ namespace MyApp.Controllers { Route("api/[controller]") ...

Issues arise due to data inconsistency stemming from the combination of a for loop and .map() function within the BACK4APP

I seem to be facing a challenge with data consistency caused by the for (const object of results) {} loop in the Sandbox Link at line41. The issue is that the results are displayed as a single result after using the .map() method. However, when I perform a ...

Changes on services do not affect the Angular component

Currently facing an issue with my Angular assignment where changing an element's value doesn't reflect in the browser, even though the change is logged in the console. The task involves toggling the status of a member from active to inactive and ...

The customer's status cannot be determined

I've encountered an issue with my TypeScript code that includes a simple if-else logic. endDate: String = ''; customerStatus: String; this.endDate = this.sampleData.customerStartDate; if (this.endDate == null) { this.customerStatus = ' ...

An item whose value is determined by the specific type of key it possesses

Consider the following scenario: enum MouseType { GENERAL_USE = 1, SPECIALIZED_USE = 2, } enum KeyboardType { GENERAL_USE = 3, SPECIALIZED_USE = 4, } interface MouseSpecifications { buttons: number; dpi: number; } interface KeyboardSpecifica ...

Unable to retrieve HTTP call response during debugging, although it is visible in the browser

When I send an HTTP request to create a record, I am able to see the added record id in the Network section of browsers like Chrome and Firefox. However, when I try to debug the code and retrieve the same id value, I encounter difficulties. I have tried us ...

Bar chart in Highcharts vanishing following the update from version 10.2.1 to 10.3.1

I've been in the process of updating my highcharts to the latest version, but I've hit a roadblock. Specifically, I have a bar chart set up with the following configuration: { chart: { type: 'bar', ...

On MacOS, VSCode encounters an issue with updating TypeScript imports when files are moved

I recently started transitioning a project from a mixed JS/TS setup to fully TypeScript. The project's server is hosted on AWS Lambda, and I have a tsconfig file at the root level as well as one in the /lambdas directory. One issue I've encounte ...

Guide to Rolling a Set of 5 Dice

I am looking to develop a game involving 5 dice. I have already created a function to roll one die using a random method, but I am unsure how to extend this functionality to the remaining four dice without having to create a separate method for each one. ...

I am experiencing issues with the customsort function when trying to sort a column of

Seeking assistance with customizing the sorting function for a Date column in a primeng table. Currently, the column is displaying data formatted as 'hh:mm a' and not sorting correctly (e.g. sorting as 1am, 1pm, 10am, 10pm instead of in chronolog ...

Angular's Spanning Powers

How can I make a button call different methods when "Select" or "Change" is clicked? <button type="button" class="btn btn-default" *ngIf="!edit" class="btn btn-default"> <span *ngIf="isNullOrUndefined(class?.classForeignId)">Select</spa ...

What might be the reason behind Array concatenation causing an issue in TypeScript?

I am relatively new to TypeScript and recently encountered an issue while working with classes. class DataStorage { private data:string[] = []; addItem(item: string){ this.data.push(item); } removeItem(item: string){ ...

Access PDF document in a fresh tab

How can I open a PDF file in a new tab using Angular 6? I have tried the following implementation: Rest controller: @RestController @RequestMapping("/downloads") public class DownloadsController { private static final String EXTERNAL_FILE_PATH = "/U ...

Error: Attempting to access an undefined property ('call') on Next.js is causing a TypeError

Exploring the realms of Next.js and Typescript for a new project! My goal is to utilize next.js with typescript and tailwind CSS by simply entering this command: npx create-next-app -e with-tailwindcss my-project Smooth sailing until I hit a snag trying t ...

Error occurs after upgrading React app to vite due to node-fetch issue

I'm a bit perplexed by this issue. Transitioning the build tool to vite has been seamless except for encountering this error: No matching export in "node_modules/node-fetch/lib/index.mjs" for import "RequestInit" No matching expor ...

The Angular 2 and TypeScript error stating that the argument of type response is not assignable is causing issues

In my Angular application, I have a service that includes a value defined as: private client_comments = new BehaviorSubject([]); When attempting to update this value with the response from an HTTP request, I encountered the following error message: A ...

Incompatibility issues between NestJS and socket.io package

After diligently following the documentation, I attempted to install and work with socket.io on nestjs. However, I encountered multiple issues when installing packages. Despite trying different methods to update the package, nothing seemed to resolve the i ...

Angular is unable to iterate through a collection of ElementRef instances

My list of ElementRef contains all my inputs, but adding listeners to them seems to indicate that textInputs is empty even though it's not. @ViewChildren('text_input') textInputs!: QueryList<ElementRef>; ngAfterViewInit(): void { ...

Update the function's argument type signature if the current argument is a function with properties

Looking for input on a potential title change, but for now, here are the details of my specific use case: I'm currently developing a library that facilitates executing methods remotely and accessing properties across serialized boundaries like those ...