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

如何在typescript中将两个部分合并成一个完整的对象?

  •  4
  • Tom  · 技术社区  · 8 年前

    See a playground of this question here

    我有一个需要所有道具的界面。但是,创建对象是一个两步过程。因此我计划创建2 Partial 对象的版本,然后将它们合并在一起以满足非部分接口的要求。例子:

    interface IComplete {
        a: string,
        b: string
    }
    
    const part1: Partial<IComplete> = {
        a: 'hello'
    }
    
    const part2: Partial<IComplete> = {
        b: 'world'
    }
    
    const together: IComplete = {
        ...part1,
        ...part2
    }
    

    尽管 together 总是完整的,编译器会抱怨:

    键入{a?:字符串;b?:string;}'不能分配给类型 “完成”。属性“a”在类型{a中是可选的?:字符串;b?以下内容: string;},但在类型“icomplete”中是必需的。

    有什么方法可以达到这个目的吗?对于我的案例来说,重要的是接口 IComplete 使成为部分的。也就是说,道具A和B从不为空或未定义。

    3 回复  |  直到 8 年前
        1
  •  5
  •   jcalz    8 年前

    @兰卡瓦诺的回答很好。一种方法可以让类型推断完成它的工作,同时仍然获得编译器的好处,确保 part1 part2 Partial<IComplete> 使用如下的帮助函数:

    interface IComplete {
      a: string,
      b: string,
      c: (x: string) => number,
      d: (x: number) => string
    }
    
    // helper function
    const asPartialIComplete = <T extends Partial<IComplete>>(t: T) => t;
    
    const part1 = asPartialIComplete({
      a: 'hello',
      c: (x) => x.length
    })
    
    const part2 = asPartialIComplete({
      b: 'world',
      d: (x) => x + ""
    });
    
    const together: IComplete = {
      ...part1,
      ...part2
    }
    

    在上面,两个 第一部分 第二部分 受到 asPartialIComplete 有效 部分<icomplete> 对象(因此 c d 方法推断为 string number 分别)。但是 第一部分 第二部分 足够窄,编译器可以意识到 typeof part1 & typeof part2 IComplete 是的。

    希望这也有帮助。祝你好运!

        2
  •  2
  •   Ryan Cavanaugh    8 年前

    最简单的方法是删除类型注释并让类型推断完成其工作:

    interface IComplete {
        a: string,
        b: string
    }
    
    const part1 = {
        a: 'hello'
    }
    
    const part2 = {
        b: 'world'
    }
    
    const together: IComplete = {
        ...part1,
        ...part2
    }
    

    这确实有一些有害的影响,例如 part1 part2 无法获取推断类型。

    相反,你可以使用 Pick -不幸的是,在使用这种方法时,您必须写出从每种类型中选择的键:

    interface IComplete {
        a: string,
        b: string,
        c: number
    }
    
    const part1: Pick<IComplete, "a"> = {
        a: 'hello'
    }
    
    const part2: Pick<IComplete, "b" | "c"> = {
        b: 'world',
        c: 43
    }
    
    const together: IComplete = {
        ...part1,
        ...part2
    }
    
        3
  •  1
  •   Hyuck Kang    8 年前

    坦率地说,我不完全理解为什么typescript transpiler不允许这种语法。

    但下面的代码可以绕过它,实现你想要的。

    interface IComplete {
        a: string,
        b: string
    }
    
    const part1: Partial<IComplete> = {
        a: 'hello'
    }
    
    const part2: Partial<IComplete> = {
        b: 'world'
    }
    
    const together: IComplete = {
        ...part1,
        ...part2
    } as IComplete
    
    推荐文章