【问题标题】:How do you specify that a class property is an integer?你如何指定一个类属性是一个整数?
【发布时间】:2012-10-15 14:25:58
【问题描述】:

我正在尝试使用TypeScript,在创建一个包含ID 字段的类的过程中,应该是integer,我有点困惑。

首先,在带有 TypeScript 插件的 Visual Studio 2012 中,我在智能感知类型列表中看到了 int。但是我得到一个编译错误,上面写着:

当前作用域中不存在名称“int”。

我查看了语言规范,只看到以下原始类型:numberstringbooleannullundefined。没有integer 类型。

所以,我有两个问题:

  1. 我应该如何向我班级的用户表明特定字段不仅仅是number,而是integer(绝不是floating 点或decimal 数字)?

  2. 如果 int 不是有效类型,为什么我会在智能感知列表中看到它?

更新:到目前为止,我得到的所有答案都是关于 JavaScript 没有 int 类型,在运行时很难强制执行 int 类型......我知道这一切。我在问是否有TypeScript 方法向我的班级用户提供注释,该字段应该是integer。也许是某种特定格式的评论?

【问题讨论】:

  • 不,它也不是我的应用程序中的有效 ID。 10 将是一个有效的 ID。
  • 验证字段并确保只接受整数值的一种方法是创建一个验证方法,该方法首先将任何可能的输入值转换为字符串,使用 RegEx 来检查该值.) 没有小数点,或 b.) 如果存在小数点,则所有后续字符都为零。之后,该方法转换回数字类型并将结果传递给需要约束的字段。

标签: typescript


【解决方案1】:
  1. 我认为没有直接的方法来指定数字是整数还是浮点数。在 TypeScript 规范第 3.2.1 节我们可以看到:

    "...Number 基元类型对应于类似名称的 JavaScript 基元类型,表示双精度 64 位格式的 IEEE 754 浮点值..."

  2. 我认为int 是 Visual Studio 智能感知中的一个错误。正确的是number

【讨论】:

  • 我想这就是答案。 1)您不能为数字类型指定比简单的“数字”更精细的任何东西,也没有任何公认的注释可以这样做; 2) VS 插件中有一个错误提示无效类型,可能基于 ECMA 262 保留关键字列表(包括“int”)
  • 可以实现静态int类型,但他们选择不这样做。也许他们认为实施起来太复杂了?
  • 请注意,number 不是N̶u̶m̶b̶e̶r̶,这是另一回事。使用此答案中指定的小写number ;-)
【解决方案2】:

TypeScript 是 JavaScript 的超集,它没有 int 的概念。它只有一个数字的概念,它有一个浮点数。

一般来说,编译器为强制执行 TypeScript int 类型的整数而必须做的工作量可能很大,在某些情况下,仍然无法确保在编译时只有整数会被分配,这就是为什么不能可靠地将int 添加到 TypeScript。

当您最初在 Visual Studio 中获得 intelliSense 时,工具无法确定要提供什么,因此您可以获得包括 int 在内的所有内容 - 但是一旦您处理已知类型的内容,您将获得明智的智能感知。

例子

var myInt: number;
var myString: string;

myInt. // toExponential, toFixed, toPrecision, toString
myString. // charAt, charCodeAt, concat, indexOf, lastIndexOf, length and many more...

【讨论】:

  • 但这并不能回答我关于如何注释我的类以便用户知道正确的字段类型的问题。另外,如果“int”从来都不是有效类型,为什么它会被包含在“everything”列表中?
  • 您使用public myVariable : number; 将其声明为数字。 int 是 JavaScript 中的保留字,这就是它出现在所有列表中的原因。 JavaScript int 信息:javascript.about.com/od/reference/g/rint.htm
  • public discountPercent : number 不会告诉用户它应该是小数(例如,0.10 表示 10%)还是整数(例如,10 表示 10%)。有没有办法向图书馆的用户注释什么是有效的,什么是无效的?
  • @Fenton 你说:“TypeScript 是 JavaScript 的超集,它没有 int 的概念。它只有数字的概念,它有一个浮点数。”。没错,但实际上可以在 TypeScript 中实现 int 类型,只是他们选择不这样做。
  • @Fenton "int 是 JavaScript 中的保留字" Fwiw, no longer accurate。明智的话,按 F12 并输入 int = 4; console.log(int);。它将输出4。如果它仍然是 JavaScript 中的保留字,例如 break,那么您就会遇到语法错误。但希望 VS 在过去五年半中也能赶上。尽管 TS 似乎没有,但它仍然是intless。 ;^)
【解决方案3】:

在 TypeScript 中,您可以使用标记来近似有时称为不透明类型。

// Helper for generating Opaque types.
type Opaque<T, K> = T & { __opaque__: K };

// 2 opaque types created with the helper
type Int = Opaque<number, 'Int'>;
type ID = Opaque<number, 'ID'>;

// using our types to differentiate our properties even at runtime
// they are still just numbers
class Foo {
    someId: ID;
    someInt: Int;
}

let foo = new Foo();

// compiler won't let you do this due to or markers
foo.someId = 2;
foo.someInt = 1;

// when assigning, you have to cast to the specific type
// NOTE: This is not completely type safe as you can trick the compiler 
// with something like foo.someId = 1.45 as ID and it won't complain.
foo.someId = 2 as ID;
foo.someInt = 1 as Int;

// you can still consume as numbers
let sum: number = foo.someId + foo.someInt;

这样做可以让您在代码中更明确地说明属性期望的类型,并且编译器不允许您在没有强制转换的情况下分配原始值。这不会产生任何额外的 .js 输出,您仍然可以使用这些值作为它们所基于的任何类型。在此示例中,我使用的是数字,但您也可以在字符串和其他类型上使用。

在这个例子中,你仍然可以欺骗编译器接受不是 Int 或 Id 的东西,但如果你试图将 1.45 分配为 Int 或类似的东西,它应该会跳出来。您还可以选择创建用于创建值以提供运行时验证的辅助函数。

您可以通过多种不同的方式创建“标记”类型。这是一篇好文章:https://michalzalecki.com/nominal-typing-in-typescript/

【讨论】:

  • 正如在其他地方所说,它的实际可用性有些问题,但您可以通过添加类型保护和/或 Casting-Helper 更进一步,这对于某些事情来说很容易 - 例如 Int 示例 -而其他人几乎不可能 - 比如 ID 示例:// @ts-ignore const isInt = (val: number | Int): val is Int =&gt; !(val % 1); const Integer = (val: number): Int =&gt; Math.round(val) as any;
【解决方案4】:

TypeScript 中没有 integerfloat 而是 number 类型,就像在 JavaScript 中一样。 但是如果你想告诉程序员你期望integer 类型,你可以尝试使用Type Aliases like

type integer = number;
type float = number;

// example:
function setInt(id: integer) {}

但这仍然是number 类型,你可以得到float

文档中的部分描述:
“别名实际上并没有创建新类型 - 它创建一个新名称来引用该类型。为原语起别名并不是非常有用,尽管它可以使用作为一种文档形式。”

【讨论】:

    【解决方案5】:

    这是我在 Google 上的最高结果,所以我认为我应该提供我找到的解决方案。

    使用bigint

    现在是 2020 年,bigint 已被接受,值得一提。您可以简单地执行以下操作。请注意,与number 相比,bigints 对性能的影响更大。

    const myNumber: bigint = 10n
    


    使用名义类型/标记类型/不透明类型

    另一种方法是使用标称类型,但可以说它不太符合人体工程学,我不确定它是否比bigint 快,但该模式确实可以推广到任何类型,而不仅仅是number。 TypeScript 对此没有“一流”的支持,所以你必须做一个厚颜无耻的 hack。有一个名为 newtype-ts 的库,其中包含 Integer 等常见类型,因此您可能只想使用它,但我将在下面解释其工作原理。

    首先我们定义integer 类型。

    const TAG = Symbol()
    type integer = number & { readonly [TAG]: unique symbol }
    

    TAG 确保我们有一个唯一的值,这样我们就不会意外地使用相同的键创建一个对象,并且出于同样的原因,我们也使该字段成为唯一的符号。现在,您的整数实际上不会有这个对象字段,但这很好。

    有了这个,您仍然可以使用+integer 添加到number。不好。因此,您可以通过使用函数按摩类型系统来对此处的参数强制执行类型安全。我只是将其称为警卫,并且您可以再次看到它不是特定于integers - 您可以制作更多不透明的类型并再次使用它。

    type guard = <A>(f: (...ns: Array<A>) => A, ...ns: Array<A>) => A
    const guard: guard = (f, ...ns) => f(...ns)
    

    如果您尝试使用 number 调用它

    const bad: integer = guard((a, b) => a + b as integer, myCoolInteger, 10)
    

    你会得到一个类似下面的错误

    Argument of type '10' is not assignable to parameter of type 'integer'.
      Type '10' is not assignable to type '{ readonly [TAG]: unique symbol; }'.(2345)
    

    请注意,您没有在此处强制执行返回类型(因为您必须使用 as integer),并且像 / 这样的一些运算符将返回浮点数,因此您可能仍希望进行运行时检查或添加 @987654344 @ 到 guard 的专用版本,但这至少可以确保您不会尝试同时使用两个单独的数字类型 - 假设您有 GBPUSD 并尝试添加它们,这可能不会你的意图。

    【讨论】:

    • 这很有趣,bigint 有一个类似的实例:BigInt(n) 和 n 必须是一个整数。那么,typescript 是如何表示 bigInt 类型的呢?
    • 所以我们有 bigint 用于性能损失的大整数,但仍然没有正常的整数,这实际上是 95% 的数字。天才。
    【解决方案6】:

    AssemblyScript 支持整数值(及其 asm.js 后端)。您可以使用 --jsFile 生成 JavaScript 文件。

    要手动执行此操作,您可以通过添加 | 0 来强制将值设为整数。

    这提高了性能,因为浏览器引擎现在能够使用整数,这比操作中的浮点数更快。

    说你打算写:

    function add(a: i32, b: i32) {
      return a + b
    }
    

    你应该这样写

    type i32 = number
    function add(a: i32, b: i32) {
      a = a | 0
      b = b | 0
      return a + b
    }
    

    或在 JavaScript 中(这是 asc --jsFile 生成的)

    function add(a, b) {
      a = a | 0
      b = b | 0
      return a + b
    }
    

    对于类属性:

    type i32 = number
    class MyClass {
      a: i32 = a | 0
    }
    

    【讨论】:

    • 这实际上提高了性能,因为浏览器引擎现在能够使用比浮点数(JS 中的默认数字类型)更快的整数。
    • 不错!你有任何关于该主题的资料/文章可以链接到我吗?
    • 这种风格的JS叫做Asm.js(也是WebAssembly的前身)。这是维基百科的链接。 en.wikipedia.org/wiki/Asm.js
    • 很高兴知道!我想当浮点值(即带小数的数字)传递给 i32 变量时,没有办法配置 ts 编译器发出错误?
    • 您应该为此使用 AssemblyScript。 assemblyscript.org
    【解决方案7】:

    好吧,正如您所见,typescript 没有浮点数据类型,例如 javascript 语言。只有number同时覆盖所有intdouble;也许您必须创建一个接受数字的函数并检查它是int 还是double,通过返回一些状态以防错误/成功。像这样的东西作为你的类的方法:

    function SetN(x:number) {
       var is_int = parseInt(x) === parseFloat(x);
       if(is_int) this.n = x;
       return is_int;
    }
    
    //..
    y = 10.5;
    if(SetN(y)) {
      //OK
    } else {
       //error not set y isn't a int
    }
    

    注意:它不适用于10.0,例如如果您真的不想要它,也许您必须将其转换为字符串并尝试找到.

    【讨论】:

    • 这将有助于执行运行时,但我主要感兴趣的是告知用户哪些数字是有效的。
    【解决方案8】:

    intearlier versions of javascript 中保留供将来使用关键字(如果您愿意,可以使用 ECMAScript)。但它是一个有效的词 now(其中“now”等同于“in the latest spec”)。

    例如,在 262 中它仍然是保留的,http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

    如果实现了 int 数据类型但所有编译时类型检查和转换规则都可用,这将是对 typescript 的一个很好的补充。

    【讨论】:

    • 那么,即使编译器无法识别,智能感知也可能会拾取这个“保留字”?
    【解决方案9】:

    这是一个不做拳击的implementation of number interface。我认为可以使用这种设计来创建一个 Integer 类型

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-01-20
      • 2021-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多