Существует ли синтаксис typeguard для ограничения свойства класса целым числом? - PullRequest
1 голос
/ 09 января 2020

У меня есть приложение, которое использует много валютных значений и несколько классов, которые отражают свойства «деньги».

Я планирую хранить все как целые числа и конвертировать только в десятичное представление в представлениях.

Является ли некоторый синтаксис защиты объявления свойств, который я могу использовать, чтобы гарантировать во время компиляции, что ошибка будет помечены попыткой присвоить обычный номер, который не может быть уверен, не является ли целое число одним из этих полей?

Например:

 class Account {
     name: string
     private balance : integer = 0;
     maxWithdrawal: integer = 0;
     maxOverdraft : integer = 0;
     ...

     deposit(amount : number) {
         this.balance += deposit;   // flags some kind of "deposit may not be an integer" error.
     }

 }

Ответы [ 2 ]

1 голос
/ 09 января 2020

BigInt в настоящее время является единственным целочисленным типом (кроме фиксированных наборов, таких как 1|2|3). То, что сопровождающие TS говорят :

BigInt кажется «достаточно близким» для этих случаев использования и не требует от нас изобретения нового синтаксиса на уровне выражения.

Вот два возможных решения:

1.) BigInt

class AccountBigInt {
  private balance: bigint = 4n;

  deposit(deposit: bigint) {
    this.balance += deposit;  
  }
}

const a = new AccountBigInt()
a.deposit(3n)
// a.deposit(3.3n) // error
// a.deposit(3.3)  // error

2.) Фирменный знак Integer тип

type Integer = number & { __brand__: "__integer__" } // branded primitive type

// use this as the only way / factory method to create an Integer type
const int = (val: number): Integer => {
  if (Number.isInteger(val)) return val as unknown as Integer
  throw Error("val is not an integer.")
}

const i1 = int(3)
const i2 = int(3.3) // throws at run-time
const sum = int(3) + int(4) // works, Integer is a subtype of number

class AccountBranded {
  private balance: Integer = int(4);

  deposit(deposit: Integer) {
    // wrap with int(), because this.balance + deposit returns number
    // you also could create an add function for Integer
    this.balance = int(this.balance + deposit)
  }
}

const a2 = new AccountBranded()
a2.deposit(int(3)) // works
a2.deposit(3) // error, number not assignable to Integer (OK)

Пример кода


Обновление: включено BigInt поддержка

В настоящее время BigInt не получил широкого распространения (2020-01-10). Насколько я знаю, «реальной» библиотеки полизаполнения не существует - пришлось бы изменить ядро ​​JS logi c для таких операторов, как +, - и других. Это был бы довольно сложный подход!

A Хорошо известный подход заключается в использовании библиотеки JSBI (см. Также здесь ). Как только поддержка BigInt станет лучше, вы сможете вернуться к нативному BigInt, не переписывая код с помощью babel plugin .

.
0 голосов
/ 09 января 2020

Нет, в TypeScript нет встроенного типа, который ограничивал бы значения целыми числами. Таким образом, нет способа отловить такие ошибки во время компиляции.

Если вы хотите, вы можете проверить целые числа во время выполнения. Вы можете создать собственное целое число в штучной упаковке и использовать Number.isInteger(), чтобы убедиться, что значение в штучной упаковке является целым числом. Например:

class BoxedInteger {
  public readonly value: number;

  public constructor(value: number) {
    if (!Number.isInteger(value)) {
      throw new Error(`Number is not an integer: ${value}`);
    }
    this.value = value;
  }
}

const a = new BoxedInteger(5).value; // ok, a = 5
const b = new BoxedInteger(5.5).value; // error!

[*] Примечание: имейте в виду ограничения Number.isInteger() Например: Number.isInteger(5.0000000000000001); // true

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger

...