How to unite the types of nested functions in TypeScript by creating a chain of unions

I am attempting to create a sequence of nested functions that can be linked together, with the final callback receiving a combination of all parent arguments. Here is an example of my current unsuccessful approach:

TS Playground Link

export type SomeHandler<T> = (args: T) => void;

type WithFooArgs = { foo: string }
const withFoo = <T,>(handler: SomeHandler<T & WithFooArgs>) => (args: T & WithFooArgs) => handler(args);

type WithBarArgs = { bar: string }
const withBar = <T,>(handler: SomeHandler<T & WithBarArgs>) => (args: T & WithBarArgs) => handler(args);

type WithZooArgs = { zoo: string }
const withZoo = <T,>(handler: SomeHandler<T & WithZooArgs>) => (args: T & WithZooArgs) => handler(args);


export default withFoo(withBar(withZoo((args) => {
    // I want args to be type `WithFooArgs & WithBarArgs & WithZooArgs`
})));

The objective is to have multiple such chains that can be combined in various ways.

Answer №1

Modifying the generics of withZoo(..) based on the surrounding expressions is not feasible. Instead, consider creating a single generic that can accommodate middleware-like callbacks and use the data from those callbacks to type a unified callback function as illustrated below:

export type SomeHandler<T> = (args: T) => void;

type WithFooArgs = { foo: string }
const withFoo = <T,>(handler: SomeHandler<T & WithFooArgs>) => (args: T & WithFooArgs) => handler(args);

type WithBarArgs = { bar: string }
const withBar = <T,>(handler: SomeHandler<T & WithBarArgs>) => (args: T & WithBarArgs) => handler(args);

type WithZooArgs = { zoo: string }
const withZoo = <T,>(handler: SomeHandler<T & WithZooArgs>) => (args: T & WithZooArgs) => handler(args);

// Function to calculate union of types
type UnionToIntersection<U> = 
  (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never;

function createHandler<Handler extends SomeHandler<any>>(handlers: Handler[], cb: (args: UnionToIntersection<Parameters<Parameters<Handler>[0]>[0]>) => void) {
    return (args: any) => {
        return cb(handlers.reduce((acc, cur) => cur(acc), args));
    };
}

export default createHandler([withFoo, withBar, withZoo], (args) => {
    console.log(args); // WithFooArgs & WithBarArgs & WithZooArgs
});

TypeScript Playground Link

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

Extracting and retrieving the value from the paramMap in Angular/JavaScript

How can we extract only the value from the router param map? Currently, the output is: authkey:af408c30-d212-4efe-933d-54606709fa32 I am interested in obtaining just the random "af408c30-d212-4efe-933d-54606709fa32" without the key "authke ...

Discovering the element within an array using the post method in TypeScript

When I log in to the app, it sends me a JSON file with my user permissions like this: {"StatusCode":0,"StatusMessage":"Authenticated Successfully", "Token":"eyJhbGciOiJIUzI1NiIs", "StatusDescription":{ "Role":"admin", "Permissions":["homeb ...

Issue with setInterval function execution within an Angular for loop

My goal is to dynamically invoke an API at specific intervals. However, when attempting to utilize the following code snippet in Angular 7, I encountered issues with the interval timing. I am seeking a solution for achieving dynamic short polling. ngOnIn ...

Retrieving Cookie from Angular 2 Response

I am in need of assistance as I am struggling to retrieve the cookie from the response. Being new to tsc and ng2, I can't seem to find a solution. Below is the ng2 http post method: return this._http .post('http://demo...', body, { hea ...

The character 'T' cannot be converted to a string

Here's the issue: I attempted to create a function that takes a parameter and returns the same type. To illustrate, I started with the most basic example: type Test = <T>(arg: T) => T; const test: Test = (arg: string) => arg; However, t ...

Sending various data from dialog box in Angular 8

I have implemented a Material Design dialog using Angular. The initial example had only one field connected to a single parameter in the parent view. I am now trying to create a more complex dialog that collects multiple parameters and sends them back to t ...

What is the best way to organize class usage within other classes to prevent circular dependencies?

The engine class presented below utilizes two renderer classes that extend a base renderer class: import {RendererOne} from "./renderer-one"; import {RendererTwo} from "./renderer-two"; export class Engine { coordinates: number; randomProperty: ...

What is the best way to prevent the hassle of manually reloading a VS Code extension each time I make updates

While working on my VS Code extension, I keep encountering the issue of opening a new instance of VS Code every time I run the extension to view recent changes. This becomes especially tedious when using VS Code remote and having to enter my password twice ...

Challenges with Angular observables

Struggling to make observables work has been quite the challenge for me lately. My code now resembles a chaotic battleground rather than the organized structure it once was. The dreaded "ERROR TypeError: Cannot read property 'map' of undefined" ...

How to Validate Ionic 2 Radio Button Selections with TypeScript

Imagine having a list like the one shown below: <ion-list radio-group [(ngModel)]="autoManufacturers"> <ion-list-header> Auto Manufacturers </ion-list-header> <ion-item> <ion-label>Cord</ion-label> &l ...

How can I efficiently extract a list of keys or numbers from an enum using TypeScript?

Is there a simple method to extract only the keys from an enumerator without returning both keys and values? The Object.keys() function returned 6 keys (0-5) when I tried it, likely because iterating through the enum with forEach also retrieved the values. ...

The specified 'IArguments' type does not qualify as an array type

Currently working on crafting a personalized logger. It's a fairly straightforward process, but I'm running into some errors that are muddying up my output. Here's what I have so far: @Injectable() export class Logger { log(...args: any ...

Utilizing TS2722 alongside restrictive parameters in tsconfig

I have encountered these errors due to the presence of the strictNullChecks parameter, which is activated by the strict configuration in the tsconfig.json file. It appears that when arguments.length === 2, the ab function should be available (thanks to Fun ...

Angular and the Client IP Address

I am trying to retrieve the client's local IP address within an internal network using Angular. This data will be sent to an IP address within the network without requiring authorization. I have searched extensively online but have only found methods ...

Error during Webpack Compilation: Module 'jQuery' not found in Travis CI with Mocha Test

I've been struggling to automate tests for my repository using mocha-webpack and Travis CI. The local machine runs the tests smoothly, but Travis CI hasn't been able to complete them yet due to an unresolved error: WEBPACK Failed to compile wit ...

Discovering the most recent 10 date elements in a JSON object within a React application

I have an array of objects containing a date element. My goal is to identify the 10 most recent dates from this element and display them in a table format. When I attempt to render these dates using a mapping technique that targets each data with data.date ...

Is it possible to create my TypeORM entities in TypeScript even though my application is written in JavaScript?

While I find it easier to write typeorm entities in TypeScript format, my entire application is written in JavaScript. Even though both languages compile the same way, I'm wondering if this mixed approach could potentially lead to any issues. Thank yo ...

typescript: issues with angular.bind and array mapping

Here is the code snippet I am currently working with: function parseValueFromComplexType(complexType, item) { return item[complexType]; } To bind the value of complex type, I am using angular.bind like so: let parseValueFromComplexTypeWithValue = an ...

mentioning a JSON key that includes a period

How can I reference a specific field from the JSON data in Angular? { "elements": [ { "LCSSEASON.IDA2A2": "351453", "LCSSEASON.BRANCHIDITERATIONINFO": "335697" }, { "LCSSEASON.IDA2A2": "353995", "LCSSEASON.BRANCHIDITER ...

Fix the TypeScript issue encountered during a CDK upgrade process

After upgrading to version 2.0 of CDK and running npm install, I encountered an issue with the code line Name: 'application-name'. const nonplclAppNames = configs['nonplclAppNames'].split(','); let nonplclAppNamesMatchingState ...