Distinguish between a function and a constructor during execution

As I work with TypeScript, I am creating a function that accepts an error factory as an argument. This factory can be either a class name or a function. The function looks something like this:


// Alias from class-transformer package
type ClassConstructor<T> = {
  new (...args: any[]): T;
};

function doSomething(value: number, errorFactory: () => Error | ClassConstructor<Error>) {
  if (value === 0) {
    // Zero is not allowed
    if (/* errorFactory is a class constructor */) {
      throw new errorFactory()
    } else {
      throw errorFactory()
    }
  }
}

Within this function, the errorFactory parameter can accept an Error class:

doSomething(0, Error);

Or it can receive a function that generates an Error:

doSomething(0, () => new Error());

The challenge arises because ClassConstructor is a type specific to TypeScript and does not retain its structure when compiled to JavaScript.

The typeof(Error) is recognized as a function, just like typeof(()=>{}).

So how can we determine the parameter's type? What condition should we use in the comment section for

/* errorFactory is a class constructor */
?

Answer №1

After reviewing the code snippet, it appears that the requirement is to use the constructor with new, and the function without new.

In this specific scenario, the Error can indeed be invoked without new. You can simply call it like this:

throw Error(msg); // where msg: string = The error message

To determine if a function (or constructor) should be called with or without new, the following code snippet can be utilized for testing:

// Returns:
// - True if the 'func' requires 'new'
// - False if the 'func' does not require 'new'
function isConstructor(func) {
  try {
    // Invoke without 'new'
    func();
  }
  catch (err) {
    if (/^TypeError:.*?constructor/.test(err.toString())) {
      // Indicates that it must be called with 'new'
      return true;
    }
    else {
      // If not related to constructor, throw the error
      throw new err.constructor(err.toString().substring(err.toString().indexOf(" ") + 1), {cause: err});
    }
  }
  return false;
}

// Run some tests
console.log(isConstructor("abc".constructor)); // Output: False
console.log(isConstructor(() => {}));          // Output: False
console.log(isConstructor(class {}));          // Output: True
console.log(isConstructor(Image));             // Output: True
console.log(isConstructor(throwErr));          // Output: TypeError: Another error
function throwErr() {
  throw new TypeError("Another error");
}

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

Utilizing Angular and the Kendo UI framework to customize the dimensions of a Kendo window

Is there a way to dynamically set the height and width of the kendo window based on the content of the kendo grid? Below is the code snippet for my kendo-window: <div kendo-window="Operation.OperCustWind" k-width="800" k-height="700" ...

Can someone provide a method to access the namespace of an Angular controller when utilizing the "Controller As" format?

Imagine you have an AngularJS ngController directive set up like this: <div ng-controller="SomeCtrl as herpderp">…</div> Is there a way to extract the namespace ("herpderp") from within the SomeCtrl controller itself? This could be useful f ...

Error: The function list.forEach does not exist within service.buildList [as project]

Today, I've been grappling with a challenging issue. As someone new to Typescript and Angular, I'm attempting to make a call to my backend API. However, when trying to populate an array for display, I keep encountering an error that says rawRegis ...

Is there a way to automatically send users to a different PHP file once they click "submit"?

I need to redirect to a different php file named index2.php. The username and password values are already set as follows: Username=sid, Password=yeaoklogin. When the user clicks on the Login button, they should be redirected to a page called index2.php. ...

Creating the x and y coordinates for drawImage in HTML5

Understanding the x and y axis has posed a challenge for me: //retrieve last known x and y coordinates ...code var p = $("#draggable"); var offset = p.offset(); var x = offset.left; var y = offset.top; //establish new font siz ...

Retrieve data from a JSON array using either JavaScript or PHP

Check out my code snippet: const newData = [{"new_id":"1","new_no":"1","total":"N.A"},{"new_id":"2","new_no":"3","total":"4"},{"new_id":"2","new_no":"4","total":"5"}]; Now, I need to extract specific details from this JSON data based on the 'new_no& ...

Tips for modifying the icon of a div with a click event using vanilla JavaScript

My goal is to create a functionality where clicking on a title will reveal content and change the icon next to the title. The concept is to have a plus sign initially, and upon clicking, the content becomes visible and the icon changes to a minus sign. C ...

How can serial numbers be sorted using a JavaScript If Statement based on 2 criteria?

I'm currently enrolled in a JavaScript coding course where I am tackling a task involving validating serial numbers. The requirement is to check if a serial number is valid and then add it to an array to store all the valid serial numbers. The criteri ...

Displaying a dynamic menu using Angular's ngFor loop

I am attempting to create a menu with sub-menus. The desired structure for my menu is outlined below. However, the demo I'm testing is not producing the correct structure. Check out the demo here. "Sub Test": { // Main menu "Example1":"hai",//sub ...

Styling the "Browse" button for different web browsers

Here is the code snippet I am working with: HTML: <form> <input id = "file" type="file" /> <div id="custom_button">custom button</div> </form> Jquery: $("#custom_button").on("click", function () { $("#file"). ...

Having trouble with jQuery.cookie saving my JSON data

Being new to jQuery and JSON, I find this situation quite frustrating as it seems pretty straightforward but still doesn't work for me. My ASP.NET MVC website is using AJAX (via jQuery) to load data. Everything works fine until this point. I'm ...

Attempting to leverage the combination of mocha, ES6 modules, and ts-node while utilizing the --experimental-loader option

I've been attempting to make the ts-node option --experimental-loader function alongside mocha, but so far I haven't had any success. Before I started compiling ES6 modules, running mocha tests was as simple as: "test": "nyc --reporter=html mocha ...

What is the most effective method in Vue.js for transitioning elements without the need to use v-for and v-if at the

Utilizing v-for to generate multiple <p> elements, each one animating in within a Vue <transition> component if the v-if condition is met. Below is the code snippet: <transition name="fade"> <p v-for="(quote, idx) in game.quot ...

Execute an HTTP POST request to the Node server, sending an empty object

For my project, I am attempting to send an HTTP Post request to my Node server from an html form. Despite using Body Parser and setting it up correctly, I am facing an issue where the req.body on my server is returning as an empty object. Can anyone prov ...

Enhancing external TypeScript modules

Currently, I am delving into the realm of enhancing external modules in TypeScript. I am diligently studying the official documentation and the DefinitelyTyped guides, poring over examples, and so forth. At this point, my goal is to incorporate custom prop ...

"Enhance Your Website with Drag-and-Drop Cart Functionality using HTML

Seeking assistance from anyone who has the knowledge. I've searched through similar questions on this platform but haven't been able to resolve my issue. Currently, I'm working on developing a basic shopping cart using HTML5 (Drag and Drop ...

Error: Unexpected top-level property "import/order" in ESLINT configuration

I'm in the process of setting up a guideline to include one blank line between internal and external imports. .eslintrc.json: { "parser": "@typescript-eslint/parser", "env": { "es6": true, " ...

Unable to append Jquery attribute to a div component

My code snippet is creating a div with specific classes and elements: '<div class="ctrl-info-panel col-md-12 col-centered">'+ '<h2>You do not have any projects created at the moment.</h2>'+ '<div id="t ...

webpack - compile one TypeScript file separately (2 actions)

In summary... When my Vue files are combined with background.ts, webpack processes them to create bundled vue files along with background.js I'm unable to run the background.js script I expected background.js to only contain "console.log(' ...

Change object values to capital letters

Upon retrieving myObject with JSON.stringify, I am now looking to convert all the values (excluding keys) to uppercase. In TypeScript, what would be the best way to accomplish this? myObj = { "name":"John", "age":30, "cars": [ { "name":"Ford", ...