Home > Back-end >  Variable number of generic parameters in Typescript
Variable number of generic parameters in Typescript

Time:10-13

I have a function like this in Typescript:

function combine<A, B>(p1: Parser<A>, p2: Parser<B>): Parser<A | B> { … }

Is it possible to type it for variable number of type variables (A, B, C, …) and correctly set the result type to Parser<A | B | C | …>? I know I can do this by writing the type signatures by hand for different arities:

function combine<A>(p1: Parser<A>): Parser<A>;
function combine<A, B>(p1: Parser<A>, p2: Parser<B>): Parser<A | B>;
// …and so on…
function combine(...parsers: Parser<any>[]): Parser<any> { … }

Is that the only option?

PS. I was looking at this similar question, but the types are a bit above my head and I don’t know whether it’s the same case or not (the “endless union type” looks like an extra requirement here).

CodePudding user response:

Here's how you you can infer the result type based on the arguments. Probably that's what you're trying to achieve

function combine<T extends string>(...ps: Parser<T>[]): typeof ps extends Array<infer R> ? R : never {
    throw new Error('not implemented')
}

TS Playground

CodePudding user response:

It is possible to implement it with array of generic types instead of unions. You can do in few ways:

  • Create a type and has abbility to do many arrow function implementation

    type ParserFunc<T extends any[]> = (...args: {
      [P in keyof T]: T[Parser<P>]
    }) => Parser<T[number]>
    
    const function1: ParserFunc<[string,number]> = (p1, p2) => { ... }  // => Parser<string | number>
    const function2: ParserFunc<[string,string]> = (p1, p2) => { ... }  // => Parser<string>
    const function3: ParserFunc<[string,boolean]> = (p1, p2) => { ... } // => Parser<string | boolean>
    
  • Create a single standart function

    function combineParser<T extends any[]>(...args: {
      [P in keyof T]: T[Parser<P>]
    }): Parser<T[number]> {
      // ...
    }
    
    combineParser(1,'2',true, null) // => Parser<number | string | boolean | null>
    
  • Related