代码之家  ›  专栏  ›  技术社区  ›  mpen

类型脚本3参数列表交叉点类型

  •  8
  • mpen  · 技术社区  · 6 年前

    TypeScript 3 改进的参数列表。

    我在看你的类型定义 Object.assign ,它看起来像这样:

    interface ObjectConstructor {
        assign<T, U>(target: T, source: U): T & U;
        assign<T, U, V>(target: T, source1: U, source2: V): T & U & V;
        assign<T, U, V, W>(target: T, source1: U, source2: V, source3: W): T & U & V & W;
        ...
    

    我想知道我们现在是否可以在不重载的情况下重写该方法签名?i、 e.我们可以表示返回值是所有输入参数的交集吗,或者这仍然是不可能的?

    我需要一个非常类似的函数。

    2 回复  |  直到 6 年前
        1
  •  12
  •   y2bd    6 年前

    让我们从将类型的元组转换为元组中类型的并集开始:

    type TupleTypes<T> = { [P in keyof T]: T[P] } extends { [key: number]: infer V } ? V : never;
    type A = TupleTypes<[1, "hello", true]>; // === 1 | "hello" | true
    

    然后我们向 this answer 要从类型并集转换为类型交集,请执行以下操作:

    type UnionToIntersection<U> = (U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never;
    type B = UnionToIntersection<A>; // === 1 & "hello" & true
    

    现在我们有了它,让我们为它写一个包装 Object.assign :

    function assign<T extends object, S extends object[]>(target: T, ...sources: S): T & UnionToIntersection<TupleTypes<S>> {
        return Object.assign(target, ...sources);
    }
    
    const good = assign({ a: "2" }, { b: "3" }, { c: "4" }, { d: "4" }, { g: "5" });
    // const good: { a: string; } & { b: string; } & { c: string; } & { d: string; } & { g: string; }
    
        2
  •  12
  •   jcalz    6 年前

    虽然我喜欢@y2bd的答案,但我认为如果传入的任何参数本身都是联合类型,就会有问题:

    const eitherOr = Math.random() < 0.5 ? { c: "4" } : { c: 5 };
    const notSoGood = assign({ a: "2" }, { b: "3" }, eitherOr);
    notSoGood.c; // string & number ?!
    

    你会发现 eitherOr 从一个并集转向一个交叉点 notSoGood 不是合适的类型。

    解决这个问题的一种方法是“装箱”和“取消装箱”元组,这样就可以区分作为并集的单个参数和多个参数类型的并集:

    type BoxedTupleTypes<T extends any[]> =
      { [P in keyof T]: [T[P]] }[Exclude<keyof T, keyof any[]>]
    type UnionToIntersection<U> =
      (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
    type UnboxIntersection<T> = T extends { 0: infer U } ? U : never;
    declare function assign<T, S extends any[]>(
      target: T,
      ...sources: S
    ): T & UnboxIntersection<UnionToIntersection<BoxedTupleTypes<S>>>
    

    现在,您将拥有正确的类型:

     const notSoGood = assign({ a: "2" }, { b: "3" }, eitherOr);
     notSoGood.c // string | number
    

    尽管如此,我不知道这个版本是否有自己的问题。更不用说十字路口并不是你想要的。你宁愿 overwrite properties if possible ,哪一个十字路口没有被捕捉。因此,在我们建议更改标准库之前,我们可能需要考虑TypeScript提供给我们的最佳签名。

    希望有帮助。祝你好运