显式设置可选属性与使用 TypeScript 中的 Partial 映射类型之间的区别

M. *_*Daw 2 types typescript

考虑以下简化类:

const rect = new Rectangle({
  x: 100,
  y: 100,
  width: 200,
  height: 400,
});
Run Code Online (Sandbox Code Playgroud)

Rectangle构造函数有一个可选的options对象,其中每个键也是可选的。

有两种方法可以为该options对象编写类型声明:

选项1

编写一个接口,其中每个属性都是可选的

class Rectangle {
  constructor(options?: RectangleConstructorOptions)
}

interface RectangleConstructorOptions {
  x?: number;
  y?: number;
  width?: number;
  height?: number;
}
Run Code Online (Sandbox Code Playgroud)

选项 2

编写一个需要键的接口,但在构造函数中使用Partial映射类型以使此对象的此属性可选

class Rectangle {
  constructor(options?: Partial<RectangleConstructorOptions>)
}

interface RectangleConstructorOptions {
  x: number;
  y: number;
  width: number;
  height: number;
}
Run Code Online (Sandbox Code Playgroud)

虽然我了解Partial工作原理,但我发现很难理解两者之间的区别。我什么时候会使用一种方法而不是另一种方法?如果选项对象非常大(超过 15 个属性),那会有什么不同吗?

另外,在这个用例中,选项 2 是否被认为是一种不好的做法?

我这样说是因为这意味着这些类型的使用者Partial如果要RectangleConstructorOptions在构造函数之外使用,也必须在调用站点使用,如下所示:

const options: RectangleConstructorOptions = { // ERROR!
  width: 100,
  height: 200,
}

const rect = new Rectangle(options);
Run Code Online (Sandbox Code Playgroud)

Mar*_*nek 5

在这个例子中两者的工作方式是一样的,但我认为还是选择选项 1 更好。稍后,如果您想在接口中添加一个必需的参数,则需要删除 Partial 并返回选项 1。

我看不出有任何理由在这种情况下使用 Partial。例如,它很有用。创建 Builder 类,它只需要某些接口的一些必需字段,因此您可以稍后提供其余字段。

将 Partial 和其他高级类型视为类型装饰器。只有当您已经拥有一个类型并且为了简单起见想要更改它时,才应该使用它们。在本例中,您是第一次创建类型,它独立于其他类型。

此外,为了避免在选项 2 中的呼叫站点调用部分,您始终可以创建命名别名:

interface RectangleConstructorOptionsRequired {
  x: number;
  y: number;
  width: number;
  height: number;
}

type RectangleConstructorOptions = Partial<RectangleConstructorOptionsRequired>;
Run Code Online (Sandbox Code Playgroud)

在此处阅读有关此主题的更多信息:高级类型