Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript generic function overload with rest types

Is there any way (special syntax) to apply something like rest parameters to templates in TypeScript?

If question is unclear then take a look at below example and comments.

Question is - can I apply here something like rest ...Types:

function mixIt<A, B>   (a: A, b: B): A & B;
function mixIt<A, B, C>(a: A, b: B, c: C): A & B & C;

/* 
 * ??
 * If I would like to add D, E, F, etc, do I have to overwrite it like above?
 */

function mixIt<A, B, C>(...args: any[]): any{
    let mixin = <A & B & C> {};

    args.forEach( obj => {
        for(let key in obj) {
            if( ! mixin.hasOwnProperty(key) ) {
                (<any>mixin)[key] = obj[key];
            }
        }
    });

    return mixin;
}

FYI - error detection is as expected:

class X {x: number = 7;}
class Y {y: string = 'ok';}
class Z {z: boolean = false;}

let x = new X;
let y = new Y;
let z = new Z;

let xy = mixIt(x, y);
let xyz = mixIt(x, y, z);

xyz.z; // Ok;
xy.z; // Error - as expected. VS Code editor also highlights it
like image 860
fider Avatar asked Feb 13 '18 15:02

fider


1 Answers

Edit Since the original answer typescript has added support for tuples in rest parameters in 3.0. With this we can achieve the desired result without all the overloads:

type UnionToIntersection<U> = 
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

function mixIt<T extends any[]>(...args: T): UnionToIntersection<T[number]>{ 
    let mixin: any =  {};

    args.forEach( obj => {
        for(let key in obj) {
            if( ! mixin.hasOwnProperty(key) ) {
                mixin[key] = obj[key];
            }
        }
    });

    return mixin;
}

Original answer

There is no way to currently have a variable number of type parameters, there is a proposal on this.

The only way to currently do this is to add as many signatures to the functions as needed, so in your case this would be:

function mixIt<A, B>   (a: A, b: B): A & B;
function mixIt<A, B, C>(a: A, b: B, c: C): A & B & C;
function mixIt<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
function mixIt<A, B, C, D, E>(a: A, b: B, c: C, d: D, e: E): A & B & C & D & E;
function mixIt<A, B, C, D, E, F>(a: A, b: B, c: C, d: D, e: E, f: F): A & B & C & D & E &F ;
// Private signature
function mixIt(...args: any[]): any{ // no need for this to be generic
    let mixin: any =  {};

    args.forEach( obj => {
        for(let key in obj) {
            if( ! mixin.hasOwnProperty(key) ) {
                mixin[key] = obj[key];
            }
        }
    });

    return mixin;
}
like image 191
Titian Cernicova-Dragomir Avatar answered Nov 15 '22 08:11

Titian Cernicova-Dragomir