TypeScript: How to get nested functions to union their types through a chain

Sean256

What I'm trying to do is create a series of nested functions which can be chained together, and the final callback's arguments will be a union of the parents. Example of my failed attempt so far:

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 goal is to have a bunch of these which I can chain together in different ways.

sno2

You are trying to change the generics of withZoo(..) based upon the expressions around it which is not possible. You could create a single generic that takes in these middleware-like callbacks then use the data from those callbacks to type a single callback function like the following:

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);

// https://stackoverflow.com/a/50375286/10873797
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

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How to flatten nested union types in Typescript?

How to get union of value types of a nested object?

How to get type of nested union in typescript

Unable to get nested type guards to work with union types in typescript

Get union of object types in Typescript?

Typescript - Narrowing union types for nested object props

Typescript Nested Tagged/Discriminated Union Types

TypeScript – How to get a union recursively of all nested values of a const object

How Typescript infers property types of union types?

How to make a type of chain (array) of functions in typescript?

How to narrow down union of generic types in Typescript?

Typescript - how to combine Union and Intersection types

How to specify union types as object keys Typescript

How to use TypeScript union types in react

How to use generic type and union types in typescript

How to narrow union types in array with typescript?

Typescript how to deal with union types and different attributes

TypeScript: How to properly narrow a Union of Intersection Types

How do I get a union type of all primitive types that are nested values of an object?

TypeScript: How can I pass narrowing types through a series of chained functions?

"Nested" union types in elm

TypeScript how associate enam with union types and get returned object property type?

Typescript Tagged Union Types

TypeScript and Union Types

Union types with TypeScript and React

typescript union of multiple types

Overloading union types in TypeScript

Typescript union types is misleading

TypeScript union function types