Incorporating a new function into a TypeScript (JavaScript) class method

Is it possible to add a method to a method within a class?

class MyClass {
    public foo(text: string): string {
        return text + ' FOO!'
    }

    // Looking for a way to dynamically add the method `bar` to `foo`.
}

const obj = new MyClass();
console.log(obj.foo('thing'));
console.log(obj.foo.bar('other thing'));

I came across a similar case involving functions:

function Sum(x: number) { /*...*/ }
namespace Sum {
    export function empty() { /*...*/ }
}

Is there a method to achieve the same functionality with methods of a class without having to patch it after object creation?

Answer №1

To utilize the function within the classes prototype, you have the flexibility to customize it as needed. While it may not be the most visually appealing code, you can implement something along these lines:

class NewClass {
  constructor(myVar) {
    this.myVar = myVar
    this.constructor.prototype.bar.foo = (function(b) {
      console.log(this.myVar, "bar.foo called with:", b)
    }).bind(this)
  }
  bar(message) {
    return message + ' BAR!'
  }

}

const object = new NewClass("John");
object.bar.foo('item')
console.log(object.bar('demo'))

Answer №2

Although it may not be exactly what you had in mind, the following code accomplishes the desired result:

class MyClass {
  public foo: MyChildClass = new MyChildClass();
}

class MyChildClass {
  public bar(text: string): string{
    return text;
  }
}

const obj = new MyClass();
console.log(obj.foo.bar('thing'));

UPDATE After reading your response to my previous comment, I believe a simpler way to achieve your objective is by using default parameters as shown below:

function foo(text: string, snapshot = false): string{
  if(snapshot){
    return 'snapshot';
  }
  return text;
}

console.debug(foo('test'));
console.debug(foo('test', true));

With this approach, you can clearly see at the point of function call whether you are requesting a bypass or a snapshot due to the additional function names. A similar outcome can be achieved in TypeScript by substituting the arguments of `foo` with an interface containing optional properties. In other programming languages, this technique is often referred to as named parameters:

interface iFooArgs{
  text: string;
  bypass?: boolean;
  snapshot?: boolean;
}

function foo(args: iFooArgs): string {
  if(args.bypass){
    return 'bypass';
  }
  if(args.snapshot){
    return 'snapshot';
  }
  return args.text;
}

console.debug(foo({text: 'test'}));
console.debug(foo({text: 'bypass?', bypass: true}));
console.debug(foo({text: 'snapshot?', snapshot: true}));

Answer №3

UPDATE: A neat solution to this problem involves the use of intersection types:

class MyClass {

    constructor() {
        this.foo = function () {
            return "this is a"
        };

        this.foo.bar = function() {
            return "this is b"
        };
    }

    public foo: Function & { bar?: () => string };
}

const obj = new MyClass();

console.log(obj.foo());
console.log(obj.foo.bar());

Try it out in the Typescript Playground

This can be achieved by utilizing the & sign in the type declaration of the class method which combines both a Function type and an object type with a single property bar that is also a function. The property being optional in the second type is necessary to satisfy Typescript, even though in practice the assignment within the constructor completes the bar property of foo.

--- PREVIOUS answer below isn't suitable for the intended purpose

Rather than defining a method directly, consider implementing a getter accessor method for the class member 'foo' that returns an object with a function 'bar'

    class MyClass {
        get foo(): {bar: (text: string) => string} {

            // any necessary preliminary code here

            return {
                bar: (text: string) => {
                    return text + ' FOO!';
                }
            }
        }
    }

    const obj = new MyClass();
    console.log(obj.foo.bar('thing'));

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

Combining plugin setups and functionalities into a unified script

When it comes to grouping plugin initializations and scripts in a website, I often have a "tools.js" file that contains various functions, click events, and more. I prefer keeping all these script calls centralized in one file for simplicity, organization, ...

Tips for parsing text responses in React to generate hyperlinks and emphasize specific words

I'm currently tackling a React project and facing an interesting challenge. I have a text response that needs to be parsed in a way that all URLs are automatically turned into clickable hyperlinks (using anchor tags). Moreover, there's a requirem ...

The use of jQuery addClass does not produce any changes

I am trying to modify a single attribute in my class using a JavaScript function. .msg_archivedropdown:before { content:""; display: block; position:absolute; width:0; height:0; left:-7px; top:0px; border-top: 10px solid tr ...

Utilize React and Jest to handle errors by either mocking window values or resolving them

When my app attempts to inject environmental variables at runtime for docker using the window object, I encounter errors in my tests. The code snippet below shows the configuration: url config: declare const window: Window & typeof globalThis & ...

Cancel your subscription to a PubNub channel when the unload event occurs

Currently, I am developing a multiplayer game in Angular utilizing the PubNub service along with the presence add-on. One of the challenges I am facing is detecting when a player unexpectedly leaves the game. This is crucial for sending notifications to o ...

Using default JavaScriptSerializer to bind DateTime to knockout view model

Recently, I started using knockout and encountered a problem with DateTime Serialization and Deserialization when using the JavaScriptSerializer. I modified the gifts model in Steve's koListEditor example from his blog to include a new field for Modi ...

unable to configure socket.io to start listening on IPv4 address

While setting up IPV4 in Socket.IO, I encountered the following error: /var/www/js/AndroRAT/node_modules/socket.io/lib/index.js:279 opts.path = opts.path || this.path(); ^ TypeError: Cannot create property 'path' on string '0.0.0 ...

Why does Axios keep timing out despite successful testing in Postman?

Trying to set up a single request for my app using axios with express/node js. Here is the code snippet that was generated through the Postman app. I have attempted different variations by creating my own form, but I always end up with the same result. co ...

Struggling with ajax: Converting a JavaScript variable to a PHP variable

I'm trying to convert a JavaScript variable into a PHP variable in order to use it in an SQL query, but for some reason it's not working as expected. Here is the HTML code: <select id = "dep_ID" name = "dep_ID" onchange="myFunction()"> A ...

Need to return to the previous page following submission

Is there a way to redirect me to the premontessori page after I submit the form? Below is my function handleSubmit: handleSubmit(event) { event.preventDefault(); <Link to='/premontessori' style={{textDecoration:'none'}} & ...

How can I use the select2 jQuery plugin with the tags:true option to ensure that selected choices do not appear again in the dropdown menu?

Transitioning to select2 for tagging from a different plugin, I'm facing a gap that I need to address in select2's functionality. Let's consider an example. Suppose my list of choices (retrieved server-side via Ajax request) is: "Dog", "Ca ...

What could be causing this error to occur? I've already got node.js installed on my system

When I enter npm init in the Visual Studio Code - Insiders terminal, I get the following error message: npm init npm : The term 'npm' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the ...

The jQuery UI accordion fails to function properly after refreshing the data

I am facing an issue with my HTML page where data is loaded dynamically into accordions. The accordion functionality is implemented inside a function, which is called at regular intervals to refresh the data. Initially, the accordion displays correctly, bu ...

I seem to be having trouble getting the home page to display properly in the app, even though I believe my code is correct. I would greatly appreciate any help in identifying the mistake

I have been struggling to render the HomePage using react Router for the past two days. I would greatly appreciate any support you can provide. Despite my numerous attempts, I have been unable to solve this problem. I even tried tools like chatgpt but al ...

How to use JQuery UI sortable to automatically scroll to the bottom of the page

Having trouble with a few sortable tables and here is how I initialized the sortable object: var options = { helper: customHelper, handle: ".moveTargetDeliverables", containment: "#fieldset_deliverables_summary", tolerance: 'pointer&a ...

Unable to locate any NativeScript modules for tns-core-module/ui

I'm working on a {N}-Application and facing an issue with importing Images from the tns-core-modules/ui/image module. Unfortunately, it seems that the target cannot be found within the tns-core-module. This is my code snippet: import * as ImageModul ...

SyntaxError: Unexpected '<' symbol found in JavaScript file while attempting to import it into an HTML document

This issue is really frustrating me In my public directory, there is an index.html file Previously, I had a newRelic script embedded within the HTML in script tags which was functioning properly Recently, I moved the script to a separate JavaScript file ...

Can TSLint and ESLint give a warning when a function is accessed as a property?

There have been instances where I've made this specific mistake, and I'm curious if there are any ESLint or TSLint rules in place that could detect it. if (this.isBrowser && this.imageURL) {.....} private isBrowser(): boolean{ retur ...

Unable to set options, such as the footer template, in Angular UI Typeahead

I am looking for a way to enhance the results page with a custom footer that includes pagination. I have noticed that there is an option to specify a footer template in the settings, but I am struggling to find examples of how to configure these options th ...

Error: Attempting to access the 'firstChild' property of a null object when trying to display a street view panorama with Vue.js

Looking to integrate a street view panorama using the Google Maps API in my VueJS project. I followed the documentation provided by Google maps here, and here is the basic template: <div id="map"></div> <div id="pano"></div> Her ...