Come implementare le costanti di classe in dattiloscritto?


430

In TypeScript, la constparola chiave non può essere utilizzata per dichiarare le proprietà della classe. Ciò causa un errore del compilatore con "Un membro della classe non può avere la parola chiave 'const'."

Mi trovo nella necessità di indicare chiaramente nel codice che una proprietà non deve essere modificata. Voglio che l'IDE o il compilatore si verifichino se provo ad assegnare un nuovo valore alla proprietà una volta che è stata dichiarata. Come raggiungete questo ragazzi?

Attualmente sto usando una proprietà di sola lettura, ma sono nuovo su Typescript (e JavaScript) e mi chiedo se esiste un modo migliore:

get MY_CONSTANT():number {return 10};

Sto usando il dattiloscritto 1.8. Suggerimenti?

PS: ora sto usando il dattiloscritto 2.0.3, quindi ho accettato la risposta di David

Risposte:


652

TypeScript 2.0 ha il readonlymodificatore :

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

Non è esattamente una costante perché consente l'assegnazione nel costruttore, ma molto probabilmente non è un grosso problema.

Soluzione alternativa

Un'alternativa è usare la staticparola chiave con 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

Questo ha il vantaggio di non essere assegnabile nel costruttore e di esistere solo in un posto.


31
Per accedere alle proprietà al di fuori della classe, dovrai aggiungere la exportparola chiave prima classe public staticprima della readonlyparola chiave. Vedi qui: stackoverflow.com/a/22993349
cbros2008

Domanda. Era chiaro perché hai bisogno del nome della classe per usare quella proprietà readOnly all'interno della classe stessa? 'MyClass.myReadonlyProperty'
Saiyaff Farouk,

@SaiyaffFarouk Se capisco la tua domanda, la risposta è che esistono proprietà statiche come parte della classe, non su un'istanza della classe. Quindi, si accede ad essi usando il nome della classe non una variabile che contiene un'istanza di classe.
JeffryHouser,

1
I export(moduli esterni) e la publicparola chiave non sono correlati a questa domanda / risposta, ma sul tema dell'esplicitazione, personalmente trovo estremamente facile dire che un membro è pubblico quando la parola chiave non esiste. Non mi preoccupo per questo motivo e perché aggiunge più rumore e digita inutilmente. Inoltre rende i membri pubblici più distinti da quelli contrassegnati come privateo protected. Comunque, solo la mia opinione :)
David Sherret,

E le lezioni anonime? Qualche idea su come accedere static readonly myReadOnlyPropertyquando viene dichiarata la lezione con export default class { ... }? Ho provato this.myVar, self.myVar, statico, predefinito ... non funziona ... (EDIT: default.myVar sembra essere la soluzione, ma sto ottenendo un errore di tipo)
Alcalyn

67

Le costanti possono essere dichiarate al di fuori delle classi e utilizzate all'interno della classe. Altrimenti la getproprietà è una bella soluzione

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}

6
Grazie; Sono preoccupato per questa implementazione perché non è portatile (nel modello, la costante non è in realtà parte della classe) e perde le informazioni in un ambito più ampio, ma ha il vantaggio di essere una costante reale, quindi ho vinto ' essere in grado di cambiarlo senza alzare il campanello d'allarme.
BeetleJuice

1
Capisco la preoccupazione e trovo l'uso della getproprietà molto appropriato nel tuo caso
j3ff

3
Per angular.io/docs/ts/latest/guide/style-guide.html si prega di utilizzare cael cammello anziché maiuscolo. Le maiuscole per le costanti non sono consigliate.
Vadim Kirilchuk,

12
Styleguide angolare, non styleguide TypeScript. La domanda riguardava specificamente TypeScript
VeldMuijz,

4
@Esko Credo che nel dattiloscritto la const sia limitata al file perché ogni file è un modulo. Per renderlo accessibile all'esterno, è necessario dichiararlo con export conste quindi importarlo da un altro file. Sarebbe piuttosto facile testarlo però. Basta dichiarare un constfile in un file e provare a usarlo in un altro senza esportare / importare o usarlo dalla console del browser.
BeetleJuice,

42

È possibile contrassegnare le proprietà con readonlymodificatore nella dichiarazione:

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

@vedi al libro di testo di tipo " Deep Dive" di sola lettura


11

Angolare 2 Fornisce una funzione molto bella chiamata Costanti Opache. Crea una classe e definisci tutte le costanti lì usando costanti opache.

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

Inseriscilo nei provider in app.module.ts

Sarai in grado di usarlo su tutti i componenti.

EDIT per Angular 4:

Per Angular 4 il nuovo concetto è Token di iniezione e il token opaco è obsoleto in Angular 4.

Token di iniezione Aggiunge funzionalità oltre ai token opachi, consente di allegare informazioni sul tipo sul token tramite generici TypeScript, oltre ai token di iniezione, elimina la necessità di aggiungere @Inject

Codice di esempio

Angolare 2 con token opachi

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

Angolare 4 Uso dei token di iniezione

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

I token di iniezione sono progettati logicamente sulla parte superiore dei token opachi e i token opachi sono deprecati in Angular 4.


6
più uno. Angular è stabile come un adolescente di 13 anni. ottengono funzionalità deprecate alcuni mesi dopo il rilascio. meschino.
Stavm,

1
meno uno. Questa domanda non ha nulla a che fare con Angular. Richiede una soluzione TypeScript.
Ben Nieting,

4

Utilizzare il modificatore readOnly con la costante che è necessario dichiarare oppure si può dichiarare una costante al di fuori della classe e utilizzarla specificamente solo nella classe richiesta utilizzando l'operatore get.


1

Per questo è possibile utilizzare il readonlymodificatore. Proprietà dell'oggetto che sonoreadonly possono essere assegnate solo durante l'inizializzazione dell'oggetto.

Esempio in classe:

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.

Esempio in oggetti letterali:

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

Vale anche la pena sapere che il readonlymodificatore è puramente un costrutto dattiloscritto e quando il TS viene compilato in JS il costrutto non sarà presente nel JS compilato. Quando stiamo modificando le proprietà che sono di sola lettura, il compilatore TS ci avvertirà (è JS valido).


-2

Per me nessuna delle risposte precedenti funziona. Ho dovuto convertire la mia classe statica in enum. Come questo:

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

Quindi nel mio componente aggiungo una nuova proprietà come suggerito in altre risposte

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

Quindi nel modello del mio componente lo uso in questo modo

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

EDIT: mi dispiace. Il mio problema era diverso da quello di OP. Lascio ancora questo qui se qualcun altro ha lo stesso problema di I.


L'uso di un enum per salvare le costanti non è una buona pratica in nessuna lingua.
Sangimed

È la migliore soluzione per le soluzioni attualmente disponibili. So che l'enum non dovrebbe essere usato, ma con Angular è il modo più pulito per avere costanti vincolanti.
Janne Harju,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.