我想知道什么是最好的方法,或者在同一文件中引用类常量之外时是否有任何后果。
当我声明一个简单类,当接收到无效参数时会引发错误的问题:
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;
}
}
我喜欢这种方法的地方是,我可以直接使用类代码,但前提是值是正确的和经过验证的,并且在我的课程中不会被它们分散注意力。另外,我无法选择忽略私有范围并访问其验证器。
如果验证真的很广泛,我可以选择为该类创建一个助手,然后在文件外部重构验证(不知道这是否是一个不好的做法)。
另一方面,我不知道在类声明之外使用它们的后果。
那么解决此问题的最佳方法是什么?两种解决方案都有效吗?有更好的方法吗?
答案 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;
}
}