What is the best way to implement function chaining in TypeScript?

I'm interested in implementing function chaining in typescript.

Let's consider a sample class:

export class NumberOperator {
  private num;

  constructor(initialNum) {
    this.num = initialNum;
  }

  public add(inc = 1) {
    this.num += inc;
  }
}

Using the class as (1):

let finalNumber = new NumberOperator(3);
console.log(finalNumber); // Output: 3

Using the class as (2):

let finalNumber = new NumberOperator(3).add();
console.log(finalNumber); // Output: 4

Using the class as (3):

let finalNumber = new NumberOperator(3).add().add();
console.log(finalNumber); // Output: 5

Using the class as (4):

let finalNumber = new NumberOperator(3).add().add(2).toString();
console.log(finalNumber); // Output: "6"

I would appreciate any guidance on achieving this. Thanks in advance :)

Answer №1

To create a chainable function, simply return this from the functions you wish to chain together.

class numbOp {
    private n: number;
    constructor(num: number) {
        this.n = num;
    }

    public add(inc = 1) : this { // annotation not necessary added to address comments
        this.n = this.n + inc;
        return this;
    }
    toString() { 
        return this.n;
    }

}
let finalNumber = new numbOp(3);
console.log(finalNumber + "") // Output: 3

// How to use it with one addition
let finalNumber2 = new numbOp(3).add();
console.log(finalNumber2 + "") // Output: 4

// Using it with two additions
let finalNumber3 = new numbOp(3).add().add();
console.log(finalNumber3 + "") // Output: 5

// Using it with three additions and converting to string
let finalNumber4 = new numbOp(3).add().add(2).toString();
console.log(finalNumber4) // Output: "6"

Edit

For better output in the console:

  1. Override toString method for string representation of the object
  2. Always call toString at the end of the chain
  3. Override valueOf method and use unary + operator (for binary operations)

Example for the last option:

class numbOp {
    private n: number;
    constructor(num: number) {
        this.n = num;
    }

    public add(inc = 1): this { 
        this.n = this.n + inc;
        return this;
    }
    valueOf() { 
        return this.n;
    }

}

let finalNumber2 = new numbOp(3).add();
console.log(+finalNumber2) // Output: 4
console.log(1 + (+finalNumber2)) // Output: 5
console.log(1+(finalNumber2 as any as number)) // Output: 5

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

Update and verify a collection of objects in real-time

I have a callback function that retrieves a data object from the DOM. Each time an item is selected, the function returns an object like this: $scope.fClick = function( data ) { $scope.x = data; } When ...

Adding clickable padding to a Draft.js editor can enhance the user experience and make the editing process

Is there a way to apply padding to the Draft.js Editor so that clicking on the padding area selects the Editor? If I add padding directly to the container div of the Editor, the padding displays properly but clicking on it does not enable writing in the E ...

Navigating through functions and saving outcomes

I need help creating a function that groups JSON elements based on a specific criteria, but I am having trouble with my loop. The goal is to create groups of 12 bottles and return a single JSON list. For example, in this case, the function should extract ...

How can ngx-modals detect when the modals have been closed?

I have integrated ngx-modals into my project and I am looking to add a boolean value to it. When the modals open, I want to set this boolean to "true", and when they close, I need it to be set to "false". Regardless of whether the modal is closed using the ...

Are there any benefits to utilizing the Mantra.js architectural framework?

I have found that integrating Meteor.js into a Mantra.js architecture works seamlessly. However, I am questioning the advantages of using it since it seems to slow down the running of my requests. For example, when making a dummy request in GraphQL (such ...

Issues with angular-strap popover's onBeforeShow function not functioning as expected in Angular

I am currently utilizing the angular-strap popover feature. To learn more about it, visit According to the documentation, when an onBeforeShow function is provided, it should be called before the popover is displayed. However, I am experiencing issues wit ...

Creating a flexible image layout within a container with relative positioning

I attempted to create a basic slideshow with images sliding from right to left as an animation: let slides = document.querySelectorAll('.img-container'); let l = slides.length; let i = 0; setInterval(function(){ i = (i + 1) % l; if(i == 0){ f ...

Exploring the functionality of Angular.js through QUnit testing

Is it possible to integrate angular.mock.inject() with QUnit instead of Jasmine? In the provided code snippet, angular.mock.dump is defined, but unfortunately angular.mock.inject remains undefined. <!DOCTYPE html> <html ng-app="mymodule"> & ...

Controller data is being successfully returned despite breakpoints not being hit

While working with knockout Java-script, I encountered a perplexing issue. I have an API call to a controller which has several methods that are functioning correctly. However, when I set a break point on a specific method, it never gets hit. Strangely, da ...

Issue with hidden sourcemap not loading in Chrome or Firefox during Vite build

Transitioning my react application from create-react-app to Vite has resulted in some unexpected behavior with source maps. To learn more about Vite's documentation on source maps, click here. Initially, I was thinking of using sourcemap: true, but th ...

Mocha avoids running the test

Hi everyone, I am a beginner in Node.js and JavaScript and I'm having trouble understanding why Mocha is skipping over my test. I know that I may not be using the request and supertest libraries correctly, but I really want to figure out why, when it ...

I'm looking for the Type Definitions Files (*.d.ts) for the Amazon Cognito Identity SDK. Does anyone know where I can find them and how

Where can I locate Type Definitions Files (*.d.ts) for the Amazon Cognito Identity SDK and how can I use them? I am utilizing TypeScript for Angular2 and I would like to have the code assistant readily available when implementing "AWS Cognito." While I al ...

When using React and React Router v6, make sure to implement a 404 status code response for unmatched routes

When it comes to managing unmatched routes with React Router, I have a solid understanding: <Routes> {/* Public routes */} <Route exact path="/" element={<Home />} /> // Other routes... {/* Error routes */} ...

Ways to ascertain if a view has completed rendering in JavaScript

I am currently building my application using the awesome backbone.js framework. Within my code, I have this layoutView that handles rendering the overall layout and also includes a smaller profile section. The dilemma I'm facing is with the timing o ...

Formik Alert: Update depth limit reached

Currently, I am working on an EDIT formik form that is displayed as a MODAL. The issue arises when the setState function is triggered with setState(true), causing the form to appear without any onClick event. Despite changing onClick={editStory} to onClick ...

Load the flexslider once the fancybox container is opened

In my experience, I have found flexslider and fancybox to be very useful plugins. Individually, they work perfectly fine on a website that I am currently working on. However, when I tried placing a flexslider gallery inside a fancybox div, I encountered a ...

Understanding the use of JSON and JavaScript is proving to be quite a challenge for me

Although I understand the "parse" and "stringify" methods for JSON, I am still struggling to use it effectively despite seeing many examples and questions. In a previous homework assignment, I created an image gallery with hard-coded links to images. Now, ...

How can I pass a dynamic scope variable to a JavaScript function in AngularJS that is being updated within an ng-repeat loop?

In my HTML, I have an ng-repeat loop where a variable is displayed in table rows. I want the user to be able to click on a value and pass it to a JavaScript function for further action. The code snippet below showcases my earlier version which successful ...

The JavaScript promise remains in limbo, neither resolving nor rejecting, seemingly stuck for unknown reasons

In the process of developing a node script, I encountered an issue where the images were not being ordered according to the calculated score value. The score is determined by a function named getImageScore(), which unfortunately takes a considerable amount ...

Limit DerbyJS to re-rendering specific DOM elements

Currently, DerbyJS (visit http://derbyjs.com) functions by replacing everything in the body tag of the document each time a link is clicked. Is there a way to utilize the template, but replace only the content inside #main-content instead of refreshing th ...