在typescript中使用联合类型时,如何防止分配错误?

在typescript中使用联合类型时,如何防止分配错误?,typescript,typescript-typings,Typescript,Typescript Typings,假设我有这些接口: interface FirstElement { id: string; coordinates: Coordinates; type: FirstElementTypes; options: FirstElementOptions; } interface SecondElement { id: string; coordinates: Coordinates; typ

假设我有这些接口:

   interface FirstElement {
      id: string;
      coordinates: Coordinates;
      type: FirstElementTypes;
      options: FirstElementOptions;
    }

   interface SecondElement {
      id: string;
      coordinates: Coordinates;
      type: SecondElementTypes;
      options: SecondElementOptions;
    }

    interface FirstElementDTO {
      id: string;
      type: FirstElemenTypes;
      options: FirstElementOptions;
    }

    interface SecondElementDTO {
      id: string;
      type: SecondElementTypes;
      options: SecondElementOptions;
    }
现在我想创建一个DTO对象,将这些接口映射到它们相应的DTO接口。因为它们共享相同的属性,只是选项不同,所以我想使用一个转换器函数。但是当使用像这样的类型脚本时

  private static convertElementToDTO(element: FirstElement | SecondElement): FirstElementDTO | SecondElementDTO {
    return {
      id: element.id,
      options: element.options,
      type: element.type
    };
  }
…我(显然)收到一条错误消息,告诉我这些选项不兼容。在typescript中,是否可以“告诉”一个函数,如果
FirstElement
是输入类型,
FirstElementDTO
是输出类型,反之亦然,
SecondElement
——而无需多次写入同一代码并使用多个if语句?谢谢你的帮助

这里可能有一个函数可以工作。首先,使用一些伪类型定义使此处的代码成为一个自包含的示例:

type FirstElementTypes = { FirstElementTypes: true };
type FirstElementOptions = { FirstElementOptions: true };
type SecondElementTypes = { SecondElementTypes: true };
type SecondElementOptions = { SecondElementOptions: true };
然后,我们可以这样表示您的类型,以减少代码重复:

// your types
interface FirstElementDTO {
  id: string;
  type: FirstElementTypes;
  options: FirstElementOptions;
}

interface SecondElementDTO {
  id: string;
  type: SecondElementTypes;
  options: SecondElementOptions;
}

// define elements as extension of DTOs to reduce code duplication
interface FirstElement extends FirstElementDTO {
    coordinates: Coordinates;
}

interface SecondElement extends SecondElementDTO {
    coordinates: Coordinates;
}
最后是通用函数:

// generic Pick function
function convertElementToDTO<E extends FirstElement | SecondElement>(
  element: E
): Pick<E, "id" | "options" | "type"> {
  return {
    id: element.id,
    options: element.options,
    type: element.type
  };
}


希望有帮助;祝你好运

你的职能违反了单一责任原则,随着时间的推移,它可能会做太多的工作。相反,您可以使用基于约定的映射框架,例如。我很感激这并没有回答你的问题,这只是一个建议。@BenSmith单一责任原则和编写冗余代码之间的界限是否存在普遍共识?根据我的理解,让几个代码片段做基本相同的事情会被认为是不干净的代码。我错了吗?谢谢你的链接,我会查出来的!关键是重构代码,以便进行映射的“几个代码段”使用通用代码,这就是automapper所做的。同样关于冗余的主题,在代码中,FirstElement和SecondElement可以从BaseElement派生,其中包含“id”和“type”。@BenSmith在我的实际场景中,他们确实从BaseElement派生属性。每个元素只有“选项”属性不同。但是AutoMapper看起来能帮上忙,再次感谢!感谢您花时间回复!不,实际输入元素类型在
类型
一般类型
中也有所不同。虽然您的方法似乎非常接近我想要的,但我得到了一个
属性“options”在类型Pick中是可选的,但在类型FirstElementDTO中是必需的
错误。知道为什么吗?我还没有完全掌握泛型的诀窍……我想我需要一个
FirstElementDTO
的定义,然后才能说出发生了什么。如果你在问题中对
FirstElement
的定义与错误中提到的不同,那么我也处于劣势。我编辑了我的答案以反映你编辑的代码,但我无法重现你在评论中提到的错误。努力提供一个新的IDE总是有帮助的,最好是通过一个指向在线IDE(如游乐场)的链接来演示。一如既往,这是一个愚蠢的错误。在
FirstElement
中,我将一个属性标记为可选,并忽略了它,与
SecondElement
相同。该属性在相应的DTO中不是可选的。你的建议是在操场上演示,这对我很有帮助,我以后会记住的。您的功能运行得非常好,非常感谢您抽出时间!
declare const f: FirstElementTypes;
declare const o: FirstElementOptions;
declare const c: Coordinates;
const first: FirstElementDTO = convertElementToDTO({
  id: "firstEl",
  type: f,
  coordinates: c,
  options: o
}); // okay