如何正确处理可选参数

时间:2018-08-03 00:20:53

标签: typescript interface

我正在使用Typescript,我想编写一个带有可选参数的函数。我不确定这是否是个合适的地方,因为没有问题,但这与编写干净的代码有关:

public addResource(config?: ResourceConfig): void {
  if (!config) {
    config = {} as ResourceConfig;
  }
  const resource: FormGroup = this.createResource(config); 
  this.control.push(resource);
}

private createResource({ amount, profit, load }: ResourceConfig): FormGroup {
  return new FormGroup({
    amount: new FormControl(amount || 1),
    profit: new FormControl(profit || 1),
    load: new FormControl(load || 1)
  });
}

...

interface ResourceConfig {
  amount: number;
  profit: number;
  load: number;
}

1 个答案:

答案 0 :(得分:0)

我假设您正在使用--strictNullChecks编译器选项,如果没有,则应该使用。


我认为可选参数本身不是问题,但是从您的使用看来,您似乎希望传递给ResourceConfigaddResource()的{​​{1}}对象的各个属性可能是失踪。但是这些方法的签名没有这么说。这会导致您不得不回避TypeScript的类型系统而不是使用它的情况。

特别是,行createResource()有问题。实际上,您已经使用type assertion对编译器撒谎了,因为空对象config = {} as ResourceConfig;不是{}。有时候,对编译器来说,小的谎言很有用,特别是在它们只是临时的情况下(例如,如果在那一行之后您继续在最初为空的对象中设置所有属性)。但是在这种情况下,您永远不会填充ResourceConfig的属性,因此欺骗会传递到config方法中……其中createResource()amount和{{1} }编译器认为}变量为profit,但实际上在运行时可能为load。您可以通过检查falsiness的每个值来解决这种可能性,但是如果我相信类型系统的话,这似乎是不必要的。


有不同的处理方法。一种就是说number缺少某些属性是可以的。这意味着您实际上没有undefined,而是拥有config,其中ResourceConfig是标准库中的mapped type,其definition

Partial<ResourceConfig>

所以Partial<T>等同于

type Partial<T> = { [P in keyof T]?: T[P] };

相反,您将获得:

Partial<ResourceConfig>

其中不需要类型声明,并且编译器将{ amount?: number; profit?: number; load?: number; } 中的变量称为public addResource(config?: Partial<ResourceConfig>): void { if (!config) { config = {}; // truth } const resource: FormGroup = this.createResource(config); this.control.push(resource); } private createResource({ amount, profit, load }: Partial<ResourceConfig>): FormGroup { return new FormGroup({ amount: new FormControl(amount || 1), profit: new FormControl(profit || 1), load: new FormControl(load || 1) }); } ,并且将传递给createResource构造函数的参数也称为由于number | undefined的欺骗而成为FormControl


处理此问题的另一种方法是实际上要求number|| 1,如果未定义,则为其分配有效的config

ResourceConfig | undefined

这使ResourceConfig不必担心可能的public addResource(config?: ResourceConfig): void { if (!config) { config = { amount: 1, profit: 1, load: 1 }; } const resource: FormGroup = this.createResource(config); this.control.push(resource); } private createResource({ amount, profit, load }: ResourceConfig): FormGroup { return new FormGroup({ amount: new FormControl(amount), profit: new FormControl(profit), load: new FormControl(load) }); } 变量。如果要允许createResource()undefinedamount为零,则这种方法可能更好。请注意,profit等于load,因为0 || 1是虚假的。如果您不希望1神奇地变成0,则不能使用0技巧。


无论哪种方式都行得通,并且存在许多其他解决方案。这里的主要思想是尝试利用TypeScript的类型系统,而不是规避它。

好的,希望能有所帮助。祝你好运!