如何指定类属性是整数?

Jos*_*osh 85 typescript

我正在尝试使用TypeScript,并且在创建一个具有应该是整数的"ID"字段的类的过程中,我有点困惑.

首先,在使用TypeScript插件的Visual Studio 2012中,我在intelliSense类型列表中看到"int".但是我得到一个编译错误,说"当前范围中不存在名称'int'".

我查看了语言规范,只看到以下原始类型:number,string,boolean,null和undefined.没有整数类型.

所以,我有两个问题:

  1. 我应该如何向我的班级用户表明某个特定字段不仅仅是一个"数字"而是一个整数(从不是浮点数或十进制数)?

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

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

Diu*_*lei 86

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

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

  2. 我认为int是Visual Studio intelliSense中的一个错误.正确的是number.

  • 我认为这就是答案.1)对于数字类型,您不能为简单的"数字"指定任何更细粒度的东西,也不能指定任何可识别的注释; 2)VS插件中存在一个建议无效类型的错误,可能基于ECMA 262保留关键字列表(包括"int") (2认同)

Fen*_*ton 24

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...
Run Code Online (Sandbox Code Playgroud)

  • @Fenton你说:“TypeScript是JavaScript的超集,它没有int的概念。它只有数字的概念,数字有一个浮点。”。确实如此,但实际上可以在 TypeScript 中实现“int”类型,只是他们选择不这样做。 (3认同)
  • 但这并不能回答我有关如何注释我的班级的问题,以便用户知道正确的字段类型。另外,如果“ int”永远不是有效的类型,为什么将它包含在“所有”列表中? (2认同)
  • 您可以使用“public myVariable : number;”将其声明为数字。`int` 是 JavaScript 中的保留字,这就是它出现在 everything 列表中的原因。有关 JavaScript int 的信息:http://javascript.about.com/od/reference/g/rint.htm (2认同)

Sho*_*hou 16

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

使用 bigint

现在是 2020 年并bigint已被接受,值得一提。您可以简单地执行以下操作。请注意,bigintnumber.

const myNumber: bigint = 10n
Run Code Online (Sandbox Code Playgroud)


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

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

首先,我们定义integer类型。

const TAG = Symbol()
type integer = number & { readonly [TAG]: unique symbol }
Run Code Online (Sandbox Code Playgroud)

TAG确保我们有一个独特的价值,使我们不小心使一个物体使用相同的密钥,并且我们做该领域的独特符号也出于同样的原因。现在,您的整数实际上不会有这个对象字段,但这很好。

有了这个,您仍然可以添加integernumber使用+. 不好。因此,您可以通过使用函数按摩类型系统来对此处的参数实施类型安全。我只想称它为守卫,正如你所看到的,它不是特定于integers 的——你可以制作更多不透明的类型并再次使用它。

type guard = <A>(f: (...ns: Array<A>) => A, ...ns: Array<A>) => A
const guard: guard = (f, ...ns) => f(...ns)
Run Code Online (Sandbox Code Playgroud)

如果您尝试使用 number

const bad: integer = guard((a, b) => a + b as integer, myCoolInteger, 10)
Run Code Online (Sandbox Code Playgroud)

你会得到如下错误

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

请注意,您没有在此处强制执行返回类型(因为您必须使用as integer),并且某些运算符/会返回浮点数,因此您可能仍希望进行运行时检查或将 a 添加Math.round到 的专用版本guard,但这至少会确保你不尝试使用两个单独的数字类型一起-想象一下,你有GBPUSD,并尝试添加这些,那很可能不是您所希望的。

  • 因此,我们有 bigint 来表示巨大的整数,但会带来性能损失,但仍然没有普通整数,而实际上 95% 的数字实际上都是这样的。天才。 (2认同)

Mar*_*zuk 9

像JavaScript中一样,没有integerfloat只能number键入TypeScript。但是,如果您想告诉程序员您希望integer输入类型,则可以尝试使用类型别名,例如

type integer = number;
type float = number;

// example:
function setInt(id: integer) {}
Run Code Online (Sandbox Code Playgroud)

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

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


bin*_*les 7

在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;
Run Code Online (Sandbox Code Playgroud)

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

在此示例中,您仍然可以诱使编译器接受不是Int或Id的内容,但是如果您尝试将1.45分配为Int或类似的内容,它应该会跳出。您还可以选择创建用于创建值以提供运行时验证的辅助函数。

创建“标记”类型的方法有多种。这是一篇好文章:https : //michalzalecki.com/nominal-typing-in-typescript/