Creating an instance of a class using a class decorator, with or without the 'new'

Seeking alternatives to creating class instances without using the new keyword in TypeScript, I came across this excellent solution that works seamlessly in JavaScript.

The code found in the repository mentioned https://github.com/digital-flowers/classy-decorator presents a straightforward class decorator:

var classy = function classy() {
    return function (Class) {
        var _Class = function _Class() {
            for (var _len = arguments.length, rest = Array(_len), _key = 0; _key < _len; _key++) {
                rest[_key] = arguments[_key];
            }

            return new(Function.prototype.bind.apply(Class, [null].concat(rest)))();
        };
        _Class.prototype = Class.prototype;
        return _Class;
    };
};

When trying to use it with TypeScript like this:

@classy()
class Someone{
    constructor(private name: string){}
}
debugger
let some1 = new Someone("john");
let some2 = Someone("joe")  // some2 is also an instance of Someone! but TypeScript raises an error stating it's not callable

I have yet to delve into the details of the function decorator to fully comprehend it, and it does result in TypeScript errors although it functions correctly.

Is there a method to bypass the TypeScript error when creating instances without using new (let some2 = Someone("joe"))

Answer №1

Regrettably, decorators in TypeScript do not alter the types of the entities they decorate. This means that the Someone constructor will not be recognized by the compiler as having a call signature. There has been a persistent feature request at microsoft/TypeScript#4881 to support type-level mutation with class decorators, but progress has been delayed while awaiting approval for the addition of decorators to JavaScript. This proposal has now reached Stage 3 of the TC39 process, and microsoft/TypeScript#48885 is in progress for implementing JS conformant decorators in TypeScript. However, the timeline for implementing type mutation remains uncertain. Currently, this functionality is not feasible.


The primary workaround involves treating the decorator as a standard function, as the output of functions can have different types from their inputs. For instance, creating a tsClassy function that we can assert to accept a constructor as input and return a callable constructor as output:

const tsClassy = classy() as
  <T, A extends any[], R>(ctor: T & (new (...args: A) => R)) => T & { (...args: A): R };

To utilize this workaround, we cannot directly decorate Someone. Instead, we need to apply it to a class constructor and store the output in a separate variable. Example usage could be:

const Someone = tsClassy(class Someone {
  constructor(public name: string) { } 
});
//const Someone: typeof Someone & ((name: string) => Someone)

Now, the compiler recognizes Someone as both a class constructor and a callable function:

let some1 = new Someone("john");
// let some1: Someone
console.log(some1.name) // john

let some2 = Someone("joe");
//let some2: Someone
console.log(some2.name) // joe

Playground link to code

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

Omit functions from category

This question reminds me of another question I came across, but it's not quite the same and I'm still struggling to figure it out. Basically, I need to duplicate a data structure but remove all the methods from it. interface XYZ { x: number; ...

"Unable to convert object into a primitive value" error message appears on Internet Explorer

Currently working on a webpage using Angular 7. The code is functioning perfectly in Chrome, however, I am facing an Exception error while running it in IE: An issue arises: Can't convert object to primitive value (polyfills.ts) The source of the er ...

Ensuring proper extension of Request headers in Typescript

I am having trouble retrieving the userId from req.headers, how can I fix this issue? Initially, I attempted the following: interface ISpot{ thumbnail: File, company: string, price: number, techs: string } interface IReqCustom<T& ...

Using getters in a template can activate the Angular change detection cycle

When using getters inside templates, it seems that Angular's change detection can get stuck in a loop with the getter being called multiple times. Despite researching similar issues, I have not been able to find a clear solution. Background info: I ...

Implement the CSS styles from the Parent Component into the Child Component using Angular 6

Is there a way to apply CSS from the Parent Component to style the child component in Angular 6? Please advise on how to approach this issue. How can we inherit the css styles from the Parent Component? <parent> <child> <p>hello ...

Is it possible to include the term 'public' exclusively within a .ts file in a TypeScript TSLint React environment?

I'm struggling to understand why I am encountering an error in VSCode while working on a react typescript project with tslint setup. The error message states: 'public' can only be used in a .ts file. [Also, I'm wondering why I' ...

Exploring Objects using Typescript

I need help creating a mapper for objects that allows TypeScript to recognize the returned type correctly. For example: type ExampleObject = { text: string; // this object may have properties of any type number: number; }; const object: ExampleObjec ...

What is the best method for retrieving an item from localstorage?

Seeking advice on how to retrieve an item from local storage in next.js without causing a page rerender. Here is the code snippet I am currently using: import { ThemeProvider } from "@material-ui/core"; import { FC, useEffect, useState } from "react"; i ...

Establish HTTP headers for accessing the Oxford API in an Angular 6 application

public performAutocomplete(wordInput):any { let headersOptions = { headers:{ 'Accept': 'application/json', 'app_id': 'myid', "app_key": "mykey" } as any } this.wordTyped = wordInp ...

Filter the array while maintaining its current structure

I'm struggling to create an array filter that can handle exact and partial data within a nested array structure. The challenge is maintaining the integrity of the top-level structure while filtering based on data in the second layer. Here's an ex ...

Navigating Angular single page application routes within an ASP.NET Web API project

Developed an Angular single-page application with specific routes: /messages /messages/:id By using ng serve, I can navigate to these pages at URLs like localhost:4200/messages and localhost:4200/messages/:id After building the solution, I transferred t ...

Utilizing Async/Await with Node.js for Seamless MySQL Integration

I have encountered two main issues. Implementing Async/Await in database queries Handling environment variables in pool configurations I am currently using TypeScript with Node.js and Express, and I have installed promise-mysql. However, I am open to usi ...

Exploring Improved Methods for Implementing Nested Subscriptions in Typescript

In my Typescript code for Angular 11, I am working with two observables. The first one, getSelfPurchases(), returns data objects containing information like id, user_id, script_id, and pp_id. On the other hand, the second observable, getScriptDetails(32), ...

An error occurred while trying to assign a value to a property that is undefined in Angular: attempting to set the

I am working with two interfaces export interface ClosureItem{ id:string; name:string; visibility?:boolean; } export interface ClosureAllItems{ [K:string]:ClosureItem; Financials:ClosureItem; Risk:ClosureItem; Iss ...

"I am looking for a way to incorporate animation into my Angular application when the data changes. Specifically, I am interested in adding animation effects to

Whenever I click on the left or right button, the data should come with animation. However, it did not work for me. I tried adding some void animation in Angular and placed a trigger on my HTML element. The animation worked when the page was refreshed, bu ...

What is the method for accessing the string value of a component's input attribute binding in Angular 2?

In my Angular2 application, I have a straightforward form input component with an @Input binding pointing to the attribute [dataProperty]. The [dataProperty] attribute holds a string value of this format: [dataProperty]="modelObject.childObj.prop". The mod ...

Introducing the concept of type-specific name inclusion

I am currently developing my Angular app using TypeScript with the goal of preventing redundancy through some form of generic handling. Here is where I am starting: class BaseProvider { api_url = 'http://localhost:80/api/FILL_OUT_PATH/:id&apo ...

Navigating through React Native with TypeScript can be made easier by using the proper method to pass parameters to the NavigationDialog function

How can I effectively pass the parameters to the NavigationDialog function for flexible usage? I attempted to pass the parameters in my code, but it seems like there might be an issue with the isVisible parameter. import React, { useState } from 'rea ...

The recommended filename in Playwright within a Docker environment is incorrectly configured and automatically defaults to "download."

Trying to use Playwright to download a file and set the filename using download.suggestedFilename(). Code snippet: const downloadPromise = page.waitForEvent('download', {timeout:100000}) await page.keyboard.down('Shift') await p ...

Ways to retrieve the property of an object within a view while being sourced from an observable

I am currently working with the following provider code: getWorldCities2() { return this.http.get('../assets/city.list.json') .map(res => res.json()); } Within my TypeScript code, I have implemented the following: ionViewDidLoad() { ...