0

I have this function which merge arbitrary numbers of objects

function merge(...objs) {
  return objs.reduce((res, cur) => {
    for (const key in cur) {
      res[key] = cur[key]
    }
    return res;
  }, {});
}

at first I thought this function could not be type annotated, but then I tried rest parameter which is quite similar to my merge function

const obj = {
  ...{ name: { ownName: 'Lewis' } },
  ...{ link: 'google.com' }
}
type Obj = typeof obj // I can happily get the Obj type

Then I came across this idea: when u don't know the types in advance, use generic. But how can I define rest generic types like function merge<T, U, V...>(...objs: Array<T | U | V...>)

crazyones110
  • 296
  • 3
  • 18

1 Answers1

1

The best way to infer rest arguments is using variadic tuple types

// credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
    k: infer I
) => void
    ? I
    : never;

function merge<T extends Record<PropertyKey, unknown>,
    Objs extends T[]
>(...objs: [...Objs]):UnionToIntersection<Objs[number]>
function merge<T extends Record<PropertyKey, unknown>,
    Objs extends T[]
>(...objs: [...Objs]) {
    return objs.reduce((acc, obj) => ({
        ...acc,
        ...obj
    }), {});
}

const result = merge({ a: 1 }, { b: 2 })
result.a // ok
result.b // ok

Playground

Here, in my blog, you can find more infering techniques.

As for the return type.

Objs[number] - infered as a union of all elements in the array UnionToIntersection - takes the union and merges it.

P.S. try to avoid mutations in typescript. Here you can find an information how to deal with them

  • What a nifty technique, but I can't understand why there are two function declarations, if I delete the upper one, TS will yell at me. I only use multiple function declarations under function overloading. – crazyones110 Sep 03 '21 at 15:47
  • The upper function is an overload of bottom. Docs https://www.typescriptlang.org/docs/handbook/2/functions.html#function-overloads – captain-yossarian from Ukraine Sep 03 '21 at 15:55
  • my answer was way better than this one, but I have guess – Ernesto Sep 03 '21 at 16:25
  • @captain-yossarian yeah I know it's overloading, but I can't figure out why bother overloading if only having one function declaration – crazyones110 Sep 03 '21 at 16:32
  • 1
    @crazyones110 you can get rid of overloading and just use type assertion at the end `UnionToIntersection`. Personally , I prefer to overload my function instead of assertion. I think it safer because overloads are bivariant to function declaration. It is up to you – captain-yossarian from Ukraine Sep 03 '21 at 16:51