Comment implémenter des constantes de classe en tapuscrit?

430

Dans TypeScript, le constmot clé ne peut pas être utilisé pour déclarer des propriétés de classe. Cela entraîne une erreur du compilateur avec «Un membre de classe ne peut pas avoir le mot clé« const ».»

Je me trouve dans le besoin d'indiquer clairement dans le code qu'une propriété ne doit pas être modifiée. Je veux que l'EDI ou le compilateur génère une erreur si j'essaie d'attribuer une nouvelle valeur à la propriété une fois qu'elle a été déclarée. Comment pouvez-vous y parvenir?

J'utilise actuellement une propriété en lecture seule, mais je suis nouveau sur Typescript (et JavaScript) et je me demande s'il y a une meilleure façon:

get MY_CONSTANT():number {return 10};

J'utilise tapuscrit 1.8. Suggestions?

PS: J'utilise maintenant le typo 2.0.3, j'ai donc accepté la réponse de David

BeetleJuice
la source

Réponses:

652

TypeScript 2.0 a le readonlymodificateur :

class MyClass {
    readonly myReadOnlyProperty = 1;

    myMethod() {
        console.log(this.myReadOnlyProperty);
        this.myReadOnlyProperty = 5; // error, readonly
    }
}

new MyClass().myReadOnlyProperty = 5; // error, readonly

Ce n'est pas exactement une constante car elle permet une affectation dans le constructeur, mais ce n'est probablement pas un gros problème.

Solution alternative

Une alternative consiste à utiliser le staticmot - clé avec readonly:

class MyClass {
    static readonly myReadOnlyProperty = 1;

    constructor() {
        MyClass.myReadOnlyProperty = 5; // error, readonly
    }

    myMethod() {
        console.log(MyClass.myReadOnlyProperty);
        MyClass.myReadOnlyProperty = 5; // error, readonly
    }
}

MyClass.myReadOnlyProperty = 5; // error, readonly

Cela a l'avantage de ne pas être assignable dans le constructeur et d'exister seulement en un seul endroit.

David Sherret
la source
31
Pour accéder aux propriétés de l'extérieur de la classe, vous devrez ajouter le exportmot - clé avant classainsi public staticqu'avant le readonlymot - clé. Voir ici: stackoverflow.com/a/22993349
cbros2008
Question. La raison pour laquelle vous avez besoin du nom de classe pour utiliser cette propriété readOnly dans la classe elle-même était-elle inconnue? 'MyClass.myReadonlyProperty'
Saiyaff Farouk
@SaiyaffFarouk Si je comprends votre question, la réponse est que les propriétés statiques existent dans le cadre de la classe, pas sur une instance de la classe. Ainsi, vous y accédez en utilisant le nom de classe et non une variable qui contient une instance de classe.
JeffryHouser
1
Les export(modules externes) et le publicmot-clé ne sont pas liés à cette question / réponse, mais sur le sujet de l'explicitness, je trouve personnellement extrêmement facile de dire qu'un membre est public lorsque le mot-clé n'existe pas. Je ne m'en soucie pas pour cette raison et parce qu'il ajoute plus de bruit et est inutile de taper. Cela rend également les membres du public plus distincts de ceux marqués comme privateou protected. Quoi qu'il en soit, juste mon opinion :)
David Sherret
Et les classes anonymes? Des idées sur la façon d'accéder static readonly myReadOnlyPropertylorsque la classe est déclarée avec export default class { ... }? J'ai essayé this.myVar, self.myVar, statique, par défaut ... ne fonctionne pas ... (EDIT: default.myVar semble être la solution, mais je reçois une erreur de type)
Alcalyn
67

Les constantes peuvent être déclarées en dehors des classes et utilisées dans votre classe. Sinon, la getpropriété est une bonne solution de contournement

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
j3ff
la source
6
Merci; Je m'inquiète de cette implémentation car elle n'est pas portable (dans le modèle, la constante ne fait pas réellement partie de la classe) et elle fuit des informations dans une plus grande portée, mais elle a l'avantage d'être une vraie constante, donc j'ai gagné '' t être en mesure de le changer sans sonner l'alarme.
BeetleJuice
1
Je comprends l'inquiétude et je trouve l'utilisation de la getpropriété très appropriée dans votre cas
j3ff
3
Par angular.io/docs/ts/latest/guide/style-guide.html, veuillez utiliser un caase de chameau au lieu de majuscules. Les majuscules pour les constantes ne sont pas recommandées.
Vadim Kirilchuk
12
Guide de style angulaire, pas un guide de style TypeScript .. La question concernait spécifiquement TypeScript
VeldMuijz
4
@Esko Je pense qu'en caractères dactylographiés, la const est limitée au fichier car chaque fichier est un module. Pour le rendre accessible à l'extérieur, vous devez le déclarer avec export constpuis l'importer à partir d'un autre fichier. Ce serait assez facile à tester. Déclarez simplement un constdans un fichier et essayez de l'utiliser dans un autre sans exporter / importer, ou de l'utiliser à partir de la console du navigateur.
BeetleJuice
42

Vous pouvez marquer les propriétés avec un readonlymodificateur dans votre déclaration:

export class MyClass {
  public static readonly MY_PUBLIC_CONSTANT = 10;
  private static readonly myPrivateConstant = 5;
}

@see TypeScript Deep Dive book - Lecture seule

am0wa
la source
11

Angular 2 Fournit une fonctionnalité très intéressante appelée sous forme de constantes opaques. Créez une classe et définissez-y toutes les constantes à l'aide de constantes opaques.

import { OpaqueToken } from "@angular/core";

export let APP_CONFIG = new OpaqueToken("my.config");

export interface MyAppConfig {
    apiEndpoint: string;
}

export const AppConfig: MyAppConfig = {    
    apiEndpoint: "http://localhost:8080/api/"    
};

Injectez-le dans les fournisseurs dans app.module.ts

Vous pourrez l'utiliser sur tous les composants.

EDIT pour Angular 4:

Pour Angular 4, le nouveau concept est Injection Token & Opaque token est obsolète dans Angular 4.

Jeton d'injection Ajoute des fonctionnalités au-dessus des jetons opaques, il permet de joindre des informations de type sur le jeton via des génériques TypeScript, plus des jetons d'injection, supprime la nécessité d'ajouter @Inject

Exemple de code

Angular 2 à l'aide de jetons opaques

const API_URL = new OpaqueToken('apiUrl'); //no Type Check


providers: [
  {
    provide: DataService,
    useFactory: (http, apiUrl) => {
      // create data service
    },
    deps: [
      Http,
      new Inject(API_URL) //notice the new Inject
    ]
  }
]

Angular 4 à l'aide de jetons d'injection

const API_URL = new InjectionToken<string>('apiUrl'); // generic defines return value of injector


providers: [
  {
    provide: DataService,
    useFactory: (http, apiUrl) => {
      // create data service
    },
    deps: [
      Http,
      API_URL // no `new Inject()` needed!
    ]
  }
]

Les jetons d'injection sont conçus logiquement au-dessus des jetons opaques et les jetons opaques sont déconseillés dans Angular 4.

Parth Ghiya
la source
6
un de plus. Angular est aussi stable qu'un adolescent de 13 ans. ils obtiennent des fonctionnalités obsolètes quelques mois après leur publication. petit.
Stavm
1
moins un. Cette question n'a rien à voir avec Angular. Il demande une solution TypeScript.
Ben Nieting
4

Soit utiliser le modificateur readOnly avec la constante que l'on doit déclarer, soit on peut déclarer une constante en dehors de la classe et l'utiliser spécifiquement uniquement dans la classe requise en utilisant l'opérateur get.

Krishna Ganeriwal
la source
1

Pour cela, vous pouvez utiliser le readonlymodificateur. Les propriétés d'objet qui readonlypeuvent être attribuées uniquement lors de l'initialisation de l'objet.

Exemple en cours:

class Circle {
  readonly radius: number;

  constructor(radius: number) {
    this.radius = radius;
  }

  get area() {
    return Math.PI * this.radius * 2;
  }
}

const circle = new Circle(12);
circle.radius = 12; // Cannot assign to 'radius' because it is a read-only property.

Exemple dans les littéraux d'objet:

type Rectangle = {
  readonly height: number;
  readonly width: number;
};

const square: Rectangle = { height: 1, width: 2 };
square.height = 5 // Cannot assign to 'height' because it is a read-only property

Il est également utile de savoir que le readonlymodificateur est purement une construction tapuscrit et que lorsque le TS est compilé en JS, la construction ne sera pas présente dans le JS compilé. Lorsque nous modifions des propriétés qui sont en lecture seule, le compilateur TS nous en avertira (c'est JS valide).

Willem van der Veen
la source
-2

Pour moi, aucune des réponses précédentes ne fonctionne. J'ai eu besoin de convertir ma classe statique en enum. Comme ça:

export enum MyConstants {
  MyFirstConstant = 'MyFirstConstant',
  MySecondConstant = 'MySecondConstant'
}

Ensuite, dans mon composant, j'ajoute une nouvelle propriété comme suggéré dans d'autres réponses

export class MyComponent {
public MY_CONTANTS = MyConstans;
constructor() { }
}

Ensuite, dans le modèle de mon composant, je l'utilise de cette façon

<div [myDirective]="MY_CONTANTS.MyFirstConstant"> </div>

EDIT: Désolé. Mon problème était différent de celui des OP. Je laisse toujours cela ici si certains ont le même problème que moi.

Janne Harju
la source
L'utilisation d'une énumération pour enregistrer des constantes n'est une bonne pratique dans aucune langue.
Sangimed
C'est la meilleure solution pour les solutions disponibles actuellement. Je sais que c'est la façon dont enum ne doit pas être utilisé, mais avec Angular, c'est le moyen le plus propre d'avoir des constantes liables.
Janne Harju