如何像打字稿中的其余运算符一样键入注释对象合并

How to type annotate object merging like rest operator does in typescript

我有这个功能可以合并任意数量的对象

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

起初我认为这个函数不能被类型注释,但后来我尝试了 rest 参数,这与我的 merge 函数非常相似

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

然后我想到了这个想法:当你事先不知道类型时,使用泛型。但是我怎样才能定义其余的泛型类型,比如 function merge<T, U, V...>(...objs: Array<T | U | V...>)

推断 rest 参数的最佳方法是使用 variadic tuple types

// credits goes to 
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,在我的博客中,您可以找到更多推理技巧。

至于return类型。

Objs[number] - 推断为数组中所有元素的并集 UnionToIntersection - 采用联合并合并它。

P.S。尽量避免打字稿中的突变。 Here 你可以找到如何处理它们的信息