161 votes

Comment spécifier qu'une propriété de classe est un nombre entier ?

J'expérimente avec TypeScript et en cours de création d'une classe avec une ID qui devrait être un integer j'ai été un peu confus.

Tout d'abord, dans Visual Studio 2012 avec le plugin TypeScript, je vois int dans la liste des types d'intelliSense. Mais je reçois une erreur de compilation qui dit :

le nom 'int' n'existe pas dans la portée actuelle.

J'ai examiné les spécifications du langage et je ne vois que les types primitifs suivants : number , string , boolean , null y undefined . Non integer type.

Donc, je me retrouve avec deux questions :

  1. Comment dois-je indiquer à les utilisateurs de ma classe qu'un domaine particulier n'est pas seulement number mais un integer (et jamais un floating point ou decimal ) ?

  2. Pourquoi est-ce que je vois int dans la liste intellisense si ce n'est pas un type valide ?

Mise à jour : Toutes les réponses que j'ai obtenues jusqu'à présent concernent la manière dont JavaScript n'a pas de type int, il serait difficile d'appliquer une règle de type int au moment de l'exécution... Je sais tout cela. Je demande s'il existe un TypeScript comment fournir une annotation aux utilisateurs de ma classe que ce champ doit être un integer . Peut-être un commentaire d'un format particulier ?

156voto

Diullei Points 3265
  1. Je pense qu'il n'y a pas de moyen direct de spécifier si un nombre est entier ou à virgule flottante. Dans la section 3.2.1 de la spécification TypeScript, nous pouvons voir :

    "...Le type primitif Number correspond au type primitif JavaScript de même nom et représente des valeurs à virgule flottante IEEE 754 en double précision et au format 64 bits..."

  2. Je pense int est un bogue dans Visual Studio intelliSense. La solution correcte est number .

43voto

Steve Fenton Points 55265

TypeScript est un sur-ensemble de JavaScript, qui n'a pas le concept d'un int. Il a seulement le concept d'un nombre, qui a un point flottant.

D'une manière générale, la quantité de travail que le compilateur devrait effectuer pour imposer que seuls des nombres entiers soient attribués à un type int de TypeScript pourrait potentiellement être massive et, dans certains cas, il ne serait toujours pas possible de garantir au moment de la compilation que seuls des nombres entiers seront attribués, ce qui explique pourquoi il n'est pas possible d'ajouter de manière fiable un paramètre int à TypeScript.

Lorsque vous obtenez initialement intelliSense dans Visual Studio, il n'est pas possible pour l'outil de déterminer ce qu'il faut fournir, donc vous obtenez tout, y compris int - mais une fois que vous avez affaire à quelque chose d'un type connu, vous obtenez intelliSense sensible.

Ejemplos

var myInt: number;
var myString: string;

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

29voto

bingles Points 1257

En TypeScript, vous pouvez approximer ce que l'on appelle parfois un type opaque en utilisant un marqueur.

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

Cela vous permet d'être plus explicite dans votre code quant aux types attendus par vos propriétés, et le compilateur ne vous permettra pas d'assigner une valeur primitive sans un cast. Cela ne produit pas de sortie .js supplémentaire, et vous pouvez toujours consommer et utiliser les valeurs comme les types sur lesquels elles sont basées. Dans cet exemple, j'utilise des nombres, mais vous pouvez également utiliser des chaînes de caractères et d'autres types.

Vous pouvez toujours tromper le compilateur en acceptant quelque chose qui n'est pas un Int ou un Id dans cet exemple, mais il devrait s'en rendre compte si vous essayez d'assigner 1,45 comme Int ou quelque chose comme ça. Vous avez également la possibilité de créer des fonctions d'aide que vous utilisez pour créer vos valeurs afin de fournir une validation à l'exécution.

Il y a plusieurs façons de créer des types "marqués". Voici un bon article : https://michalzalecki.com/nominal-typing-in-typescript/

22voto

Mariusz Charczuk Points 379

Il n'y a pas integer o float mais number en TypeScript comme en JavaScript. Mais si vous voulez dire au programmeur que vous vous attendez à ce que integer vous pouvez essayer d'utiliser Type d'alias comme

type integer = number;
type float = number;

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

mais c'est toujours number et vous pouvez obtenir float .

Partie de la description de la documentation :
"L'aliasing ne crée pas réellement un nouveau type, il crée un nouveau nom pour faire référence à ce type. L'aliasage d'une primitive n'est pas terriblement utile, bien qu'il puisse être utilisé comme une forme de documentation."

19voto

Shou Points 714

C'est le premier résultat que j'ai trouvé sur Google, alors je me suis dit que je devais fournir les solutions que j'ai trouvées.

Utilisation de bigint

Maintenant que nous sommes en 2020 et que bigint a été acceptée, elle mérite d'être mentionnée. Vous pouvez simplement faire ce qui suit. Attention bigint ont un impact plus important sur les performances par rapport à l'option number .

const myNumber: bigint = 10n

Utilisation d'un type nominal / type balisé / type opaque

Une alternative est d'utiliser un type nominal, mais c'est sans doute moins ergonomique et je ne suis pas sûr que cela soit plus rapide que bigint mais le modèle s'applique à n'importe quel type, et pas seulement à l'anglais. number . TypeScript ne dispose pas d'une prise en charge "de première classe" pour cela, il faut donc faire un piratage insolent. Il existe une bibliothèque pour cela, appelée newtype-ts qui comprend des types courants comme Integer donc vous pouvez l'utiliser, mais je vais vous expliquer le fonctionnement ci-dessous.

Pour commencer, nous définissons le integer type.

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

Le site TAG assure que nous avons une valeur unique afin de ne pas créer accidentellement un objet avec la même clé, et nous faisons du champ un symbole unique aussi pour la même raison. Maintenant, votre entier n'aura pas réellement ce champ d'objet mais ce n'est pas grave.

Avec cela, vous pouvez encore ajouter integer à number en utilisant + . Ce n'est pas bon. Donc vous pouvez renforcer la sécurité de type sur les arguments ici en massant le système de type avec une fonction. Je vais juste l'appeler guard, et encore une fois, comme vous pouvez le voir, ce n'est pas spécifique à integer vous pourriez créer des types plus opaques et utiliser à nouveau cette méthode.

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

Si vous essayez de l'appeler avec un number

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

vous obtiendrez une erreur comme ci-dessous

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

Notez que vous n'imposez pas le type de retour ici (parce que vous devez utiliser la fonction as integer ) et certains opérateurs comme / renverra des nombres à virgule flottante. Vous voudrez donc probablement effectuer des vérifications au moment de l'exécution ou ajouter une fonction Math.round à une version spécialisée de guard mais cela vous permettra au moins de vous assurer que vous n'essayez pas d'utiliser deux types numériques distincts ensemble - imaginez que vous avez GBP y USD et essayer de les ajouter, ce ne serait probablement pas ce que vous vouliez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X