【问题标题】:typescript private readonly vs outside of class const [closed]typescript private readonly vs 类之外的 const [关闭]
【发布时间】:2020-01-13 16:41:32
【问题描述】:

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

当我声明一个接收无效参数时会抛出错误的简单类时会出现问题:

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 setter 永远不会在构造函数中触发,因为需要实例化该类。

因为我想让事情变得简单,我只希望这个示例类包含一个有效数字或根本不存在,所以我不想在其 上使用 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;
  }

}

我喜欢这种方法的地方在于,我可以直接进入我的课程代码,前提是值是正确且经过验证的,并且我不会在课堂上被它们分心。另外,我不能选择省略私有作用域并访问其验证器。

此外,如果验证变得非常广泛,我可以选择为该类创建一个帮助程序并在文件之外重构验证(不知道这是否是一种不好的做法)。

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

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

【问题讨论】:

  • 如果常量是原始类型(例如数字、字符串)或枚举,则使其成为类外常量。导出它。任何。这是一个声明为 const 的原语:它不会改变你。如果它是引用类型(对象、数组),并且仅当它是引用类型时,您是否应该考虑将其设为私有属性。
  • 这个问题没有正确答案,会带来很多意见,而不是基于事实的方法。一般来说,当你没有为这些修饰符的含义提供客观标准时,要求“最好”或“更好”的方法会做到这一点。
  • ^^ 因此有 3 票(包括我的票)可以关闭,主要基于意见
  • 使用类型系统的全部意义在于不依赖运行时类型检查!任何调用 myDigit.value = xx 不是 number 的代码都应该引发编译时错误。
  • @user633183 这就是它的作用!不幸的是,NaN 是一个数字 ...

标签: javascript typescript class ecmascript-6 constructor


【解决方案1】:

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

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;
  }

}

【讨论】:

  • 是的,这对我来说看起来不错,但这让我觉得二传手被浪费了,因为你有一个 set value,然后是一个 setValue 在类内。
  • 正如您所说的“该值设置器永远不会在构造函数中触发,因为需要实例化类才能这样做”,鉴于您的设置器要求,我不知道避免重复自己的不同方法.
【解决方案2】:

我会亲自介绍另一种类型,例如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。抛出错误不是一个好主意,相反,您应该正确验证输入和操作,这就是强制执行的。

【讨论】:

  • 很有趣,但这不会强制在课堂外进行检查吗?谁比类本身更清楚它可以持有哪些价值观?想象一下同一个类有 10 个属性,每个属性都有不同的类型验证。还有为什么抛出错误不是一个好主意?
  • @Julián 对,它强制开发人员直接验证输入数据和数学运算。我承认这可能会由于一些不必要的守卫而增加一些开销(似乎数字文字类型很快就会变得更强大,那么这可能会变得更优雅)
  • @Juliánn 错误在运行时抛出。这不是以某种方式处理错误,而是强制您主动检查数据,这样您还可以直接向用户提供反馈等。
  • “谁比类本身更清楚它可以保存哪些值?”,对,这就是类型指定的原因。
猜你喜欢
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-15
  • 2010-10-17
  • 2020-04-25
相关资源
最近更新 更多