Wie implementiere ich Klassenkonstanten in Typoskript?

428

In TypeScript kann das constSchlüsselwort nicht zum Deklarieren von Klasseneigenschaften verwendet werden. Dies führt dazu, dass der Compiler einen Fehler mit "Ein Klassenmitglied kann das Schlüsselwort 'const' nicht haben."

Ich muss im Code klar angeben, dass eine Eigenschaft nicht geändert werden sollte. Ich möchte, dass die IDE oder der Compiler einen Fehler macht, wenn ich versuche, der Eigenschaft einen neuen Wert zuzuweisen, sobald sie deklariert wurde. Wie erreicht ihr das?

Ich verwende derzeit eine schreibgeschützte Eigenschaft, bin jedoch neu in Typescript (und JavaScript) und frage mich, ob es einen besseren Weg gibt:

get MY_CONSTANT():number {return 10};

Ich benutze Typoskript 1.8. Vorschläge?

PS: Ich verwende jetzt Typoskript 2.0.3, also habe ich Davids Antwort akzeptiert

BeetleJuice
quelle

Antworten:

649

TypeScript 2.0 hat den readonlyModifikator :

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

Es ist nicht gerade eine Konstante, weil es die Zuweisung im Konstruktor ermöglicht, aber das ist höchstwahrscheinlich keine große Sache.

Alternative Lösung

Eine Alternative besteht darin, das staticSchlüsselwort zu verwenden mit 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

Dies hat den Vorteil, dass es im Konstruktor nicht zuweisbar ist und nur an einer Stelle vorhanden ist.

David Sherret
quelle
31
Um von außerhalb der Klasse auf die Eigenschaften zuzugreifen, müssen Sie das exportSchlüsselwort sowohl vor classals auch public staticvor dem readonlySchlüsselwort hinzufügen . Siehe hier: stackoverflow.com/a/22993349
cbros2008
Frage. War ahnungslos, warum Sie den Klassennamen benötigen, um diese readOnly-Eigenschaft in der Klasse selbst zu verwenden? 'MyClass.myReadonlyProperty'
Saiyaff Farouk
@SaiyaffFarouk Wenn ich Ihre Frage verstehe, lautet die Antwort, dass statische Eigenschaften als Teil der Klasse vorhanden sind und nicht für eine Instanz der Klasse. Sie greifen also mit dem Klassennamen zu, nicht mit einer Variablen, die eine Klasseninstanz enthält.
JeffryHouser
1
Die export(externen Module) und das publicSchlüsselwort haben nichts mit dieser Frage / Antwort zu tun, aber beim Thema Explizit fällt es mir persönlich sehr leicht zu sagen, dass ein Mitglied öffentlich ist, wenn das Schlüsselwort nicht vorhanden ist. Ich kümmere mich aus diesem Grund nicht darum und weil es mehr Rauschen hinzufügt und unnötig tippt. Es unterscheidet die öffentlichen Mitglieder auch stärker von denen, die als privateoder gekennzeichnet sind protected. Wie auch immer, nur meine Meinung :)
David Sherret
Was ist mit anonymen Klassen? Irgendwelche Ideen, wie man zugreifen kann, static readonly myReadOnlyPropertywenn die Klasse mit deklariert ist export default class { ... }? Versucht this.myVar, self.myVar, statisch, Standard ... funktioniert nicht ... (EDIT: default.myVar scheint die Lösung zu sein, aber ich
erhalte
67

Konstanten können außerhalb von Klassen deklariert und innerhalb Ihrer Klasse verwendet werden. Ansonsten ist die getEigenschaft eine schöne Problemumgehung

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
j3ff
quelle
6
Vielen Dank; Ich mache mir Sorgen um diese Implementierung, weil sie nicht portabel ist (im Modell ist die Konstante eigentlich nicht Teil der Klasse) und Informationen in den größeren Bereich verliert, aber sie hat den Vorteil, dass sie eine echte Konstante ist, also habe ich gewonnen. ' Sie können es nicht ändern, ohne Alarmglocken zu läuten.
BeetleJuice
1
Ich verstehe die Besorgnis und finde die Nutzung von getEigentum in Ihrem Fall sehr angemessen
j3ff
3
Per angle.io/docs/ts/latest/guide/style-guide.html verwenden Sie bitte Kamelkaase anstelle von Großbuchstaben. Großbuchstaben für Konstanten werden nicht empfohlen.
Vadim Kirilchuk
12
Angular Styleguide, nicht TypeScript Styleguide. Die Frage
betraf
4
@Esko Ich glaube, dass in Typoskript die Konstante auf die Datei beschränkt ist, da jede Datei ein Modul ist. Um es außerhalb zugänglich zu machen, müssten Sie es mit deklarieren export constund dann aus einer anderen Datei importieren. Wäre allerdings ziemlich einfach zu testen. Deklarieren Sie einfach eine constin einer Datei und versuchen Sie, sie in einer anderen Datei ohne Export / Import oder über die Browserkonsole zu verwenden.
BeetleJuice
42

Sie können Eigenschaften mit dem readonlyModifikator in Ihrer Deklaration markieren :

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

@see TypeScript Deep Dive Buch - Readonly

am0wa
quelle
11

Winkel 2 Bietet eine sehr schöne Funktion, die als undurchsichtige Konstanten bezeichnet wird. Erstellen Sie eine Klasse und definieren Sie alle Konstanten dort mit undurchsichtigen Konstanten.

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

Injizieren Sie es in Anbietern in app.module.ts

Sie können es für alle Komponenten verwenden.

EDIT für Angular 4:

Für Angular 4 lautet das neue Konzept Injection Token & Opaque Token ist in Angular 4 veraltet.

Injection Token Fügt Funktionen zusätzlich zu undurchsichtigen Token hinzu. Es ermöglicht das Anhängen von Typinformationen an das Token über TypeScript-Generika sowie Injection Token, sodass @Inject nicht mehr hinzugefügt werden muss

Beispielcode

Winkel 2 Verwenden undurchsichtiger Token

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
    ]
  }
]

Winkel 4 Verwenden von Injektionstoken

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!
    ]
  }
]

Injektionsmarker werden logisch über undurchsichtigen Token entworfen und undurchsichtige Token sind in Winkel 4 veraltet.

Parth Ghiya
quelle
6
Plus eins. Angular ist so stabil wie ein 13-jähriger Teenager. Einige Monate nach der Veröffentlichung werden Features veraltet. kleinlich.
Stavm
1
minus eins. Diese Frage hat nichts mit Angular zu tun. Es wird eine TypeScript-Lösung angefordert.
Ben Nieting
4

Verwenden Sie entweder den Modifikator readOnly mit der Konstante, die deklariert werden muss, oder deklarieren Sie eine Konstante außerhalb der Klasse und verwenden Sie sie speziell nur in der erforderlichen Klasse mit dem Operator get.

Krishna Ganeriwal
quelle
1

Hierfür können Sie den readonlyModifikator verwenden. readonlyObjekteigenschaften, die nur während der Initialisierung des Objekts zugewiesen werden können.

Beispiel in Klassen:

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.

Beispiel in Objektliteralen:

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

Es ist auch wichtig zu wissen, dass der readonlyModifikator ein reines Typoskript-Konstrukt ist und wenn der TS zu JS kompiliert wird, das Konstrukt im kompilierten JS nicht vorhanden ist. Wenn wir schreibgeschützte Eigenschaften ändern, warnt uns der TS-Compiler davor (es ist gültiges JS).

Willem van der Veen
quelle
-2

Für mich funktioniert keine der früheren Antworten. Ich musste meine statische Klasse in enum konvertieren. So was:

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

Dann füge ich in meiner Komponente eine neue Eigenschaft hinzu, wie in anderen Antworten vorgeschlagen

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

Dann verwende ich es in der Vorlage meiner Komponente so

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

EDIT: Entschuldigung. Mein Problem war anders als bei OPs. Ich lasse das immer noch hier, wenn jemand das gleiche Problem hat wie ich.

Janne Harju
quelle
Die Verwendung einer Aufzählung zum Speichern von Konstanten ist in keiner Sprache eine gute Vorgehensweise.
Sangimed
Es ist die beste Lösung für derzeit verfügbare Lösungen. Ich weiß, dass Enum nicht verwendet werden sollte, aber mit Angular ist es am saubersten, bindbare Konstanten zu haben.
Janne Harju