打字稿私人只读vs类const外

时间:2019-09-11 19:51:51

标签: javascript typescript class ecmascript-6 constructor

我想知道什么是最好的方法,或者在同一文件中引用类常量之外时是否有任何后果。

当我声明一个简单类,当接收到无效参数时会引发错误的问题:

export class Digit {
  private _value: number = null;

  constructor(value: number) {
    this._value = value;
  }

  set value(value: number) {
    if (isNaN(value)) { throw new Error('Received NaN as digit.'); }

    this._value = value;
  }

  get value() {
    return this._value;
  }

}

value 设置器永远不会在构造函数中触发,因为需要实例化该类。

因为我想保持简单,所以我只想让这个示例类保留一个有效数字或根本不存在,因此我不想在其 value 上使用null实例化它。 。这导致我看到以下代码:

export class Digit {
  private _value: number = null;

  constructor(value: number) {
    if (isNaN(value)) { throw new Error('Received NaN as digit.'); }

    this._value = value;
  }

  set value(value: number) {
    if (isNaN(value)) { throw new Error('Received NaN as digit.'); }

    this._value = value;
  }

  get value() {
    return this._value;
  }

}

哪个工作正常,但现在我要重复一遍!想象一下对10个或更多字段进行这样的验证。

所以我考虑了两种解决方案:

1-重构为类内部的验证函数

export class Digit {
  private _value: number = null;

  private readonly validateValue = function (value: number): number {
    if (isNaN(value)) { throw new Error('Received NaN as digit.'); }

    return value;
  };

  constructor(value: number) {
    this._value = this.validateValue(value);
  }

  set value(value: number) {
    this._value = this.validateValue(value);
  }

  get value() {
    return this._value;
  }

}

我喜欢这种方法,因为所有业务逻辑都包含在类内部。但是,如果您选择不尊重私有范围,它仍然可以实现。 我不喜欢的事情是,随着越来越多的字段和验证的添加,该类很容易变得混乱,因为您可能想要在知道实例值正确的情况下修复某些行为,这使您分心

2-重构到类之外但在同一文件中的验证函数中

const validateValue = function (value: number): number {
  if (isNaN(value)) { throw new Error('Received NaN as digit.'); }

  return value;
};

export class Digit {
  private _value: number = null;

  constructor(value: number) {
    this._value = validateValue(value);
  }

  set value(value: number) {
    this._value = validateValue(value);
  }

  get value() {
    return this._value;
  }

}

我喜欢这种方法的地方是,我可以直接使用类代码,但前提是值是正确的和经过验证的,并且在我的课程中不会被它们分散注意力。另外,我无法选择忽略私有范围并访问其验证器。

如果验证真的很广泛,我可以选择为该类创建一个助手,然后在文件外部重构验证(不知道这是否是一个不好的做法)。

另一方面,我不知道在类声明之外使用它们的后果。

那么解决此问题的最佳方法是什么?两种解决方案都有效吗?有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

我将亲自介绍另一种类型,例如NotNaN

type NotNaN = number & { __notNaN: true };

然后您可以为此编写验证器

function notNaN(n: any): n is NotNaN {
  return !isNaN(n);
}

并相应地键入您的类属性:

class Digit {
  constructor(public value: NotNaN) { }
}

然后您可以编写如下内容:

let digit = new Digit(12 as NotNaN);
let someValue = +prompt("Surprise me!");

// Properly checked, works:
if(notNaN(someValue)) {
  digit.value = someValue;
}

// Not properly checked:
digit.value = someValue;
// TypeError: type 'number' is not assignable to type 'NotNaN'

这样,您可以完全避免使用getter / setter方法。抛出错误不是一个好主意,相反,您应该正确地验证输入和操作,这就是要执行的操作。

答案 1 :(得分:0)

我不确定这里是否有“正确”的答案。我个人更希望有一个用于设置值的实现,然后您可以从构造函数中调用该实现。

export class Digit {
  private _value: number = null;

  constructor(value: number) {
    this.setValue(value);
  }

  set value(value: number) {
    this.setValue(value);
  }

  get valor() {
    return this._value;
  }

  private setValue(value: number) {
    if (isNaN(value)) { throw new Error('Received NaN as digit.'); }
    this._value = value;
  }

}