¿Cómo implementar constantes de clase en mecanografiado?

430

En TypeScript, el const palabra clave no se puede usar para declarar propiedades de clase. Al hacerlo, el compilador produce un error con "Un miembro de la clase no puede tener la palabra clave 'const'".

Necesito indicar claramente en el código que una propiedad no debe cambiarse. Quiero que el IDE o el compilador produzcan un error si intento asignar un nuevo valor a la propiedad una vez que se ha declarado. ¿Cómo logran esto?

Actualmente estoy usando una propiedad de solo lectura, pero soy nuevo en Typecript (y JavaScript) y me pregunto si hay una mejor manera:

get MY_CONSTANT():number {return 10};

Estoy usando el mecanografiado 1.8. Sugerencias?

PD: ahora estoy usando el mecanografiado 2.0.3, así que acepté la respuesta de David

Jugo de escarabajo
fuente

Respuestas:

652

TypeScript 2.0 tiene el readonlymodificador :

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

No es exactamente una constante porque permite la asignación en el constructor, pero probablemente no sea gran cosa.

Solución alternativa

Una alternativa es usar la staticpalabra clave 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

Esto tiene el beneficio de no ser asignable en el constructor y solo existir en un lugar.

David Sherret
fuente
31
Para acceder a las propiedades desde fuera de la clase, deberá agregar la exportpalabra clave antes classy public staticantes de la readonlypalabra clave. Ver aquí: stackoverflow.com/a/22993349
cbros2008
Pregunta. ¿No tenía idea de por qué necesita el nombre de la clase para usar esa propiedad readOnly dentro de la clase misma? 'MyClass.myReadonlyProperty'
Saiyaff Farouk
@SaiyaffFarouk Si entiendo su pregunta, la respuesta es que existen propiedades estáticas como parte de la clase, no en una instancia de la clase. Entonces, accede a ellos usando el nombre de la clase, no una variable que contiene una instancia de clase.
JeffryHouser
1
Los export(módulos externos) y la publicpalabra clave no están relacionados con esta pregunta / respuesta, pero sobre el tema de lo explícito, personalmente me resulta extremadamente fácil decir que un miembro es público cuando la palabra clave no existe. No me molesto con eso por esa razón y porque agrega más ruido y no es necesario escribir. También hace que los miembros públicos sean más distintos de los marcados como privateo protected. De todos modos, solo mi opinión :)
David Sherret
¿Qué pasa con las clases anónimas? ¿Alguna idea sobre cómo acceder static readonly myReadOnlyPropertycuando se declara la clase con export default class { ... }? Probé this.myVar, self.myVar, estático, predeterminado ... no funciona ... (EDITAR: default.myVar parece ser la solución, pero recibo un error de tipo)
Alcalyn
67

Las constantes pueden declararse fuera de las clases y usarse dentro de su clase. De lo contrario, la getpropiedad es una buena solución

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
j3ff
fuente
66
Gracias; Me preocupa esta implementación porque no es portátil (en el modelo, la constante no es en realidad parte de la clase) y filtra información en el alcance mayor, pero tiene la ventaja de ser una constante real, así que gané ' No poder cambiarlo sin hacer sonar las alarmas.
BeetleJuice
1
Entiendo la preocupación y considero que el uso de la getpropiedad es muy apropiado en su caso
j3ff
3
Según angular.io/docs/ts/latest/guide/style-guide.html , use camel caase en lugar de mayúsculas. No se recomienda el uso de mayúsculas para constantes.
Vadim Kirilchuk
12
Guía de estilo angular, no guía de estilo de TypeScript. La pregunta se refería específicamente a TypeScript
VeldMuijz
44
@Esko Creo que, en mecanografiado, el const se limita al archivo porque cada archivo es un módulo. Para hacerlo accesible desde el exterior, deberá declararlo export consty luego importarlo desde otro archivo. Sin embargo, sería bastante fácil de probar. Simplemente declare un consten un archivo e intente usarlo en otro sin exportar / importar, o usarlo desde la consola del navegador.
BeetleJuice
11

Angular 2 proporciona una característica muy agradable llamada como constantes opacas. Cree una clase y defina todas las constantes allí usando constantes opacas.

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

Inyectarlo en proveedores en app.module.ts

Podrá usarlo en todos los componentes.

EDITAR para Angular 4:

Para Angular 4, el nuevo concepto es Token de inyección y token opaco está en desuso en Angular 4.

El token de inyección agrega funcionalidades sobre tokens opacos, permite adjuntar información de tipo en el token a través de genéricos TypeScript, más tokens de inyección, elimina la necesidad de agregar @Inject

Código de ejemplo

Angular 2 usando tokens opacos

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 usando fichas de inyección

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

Los tokens de inyección están diseñados lógicamente en la parte superior de los tokens opacos y los tokens opacos están en desuso en Angular 4.

Parth Ghiya
fuente
66
mas uno. Angular es tan estable como un adolescente de 13 años. obtienen funciones obsoletas unos meses después de su lanzamiento. pequeño.
Stavm
1
menos uno. Esta pregunta no tiene nada que ver con Angular. Está solicitando una solución TypeScript.
Ben Nieting
4

Utilice el modificador readOnly con la constante que necesita declarar o puede declarar una constante fuera de la clase y úsela específicamente solo en la clase requerida usando el operador get.

Krishna Ganeriwal
fuente
1

Para esto puedes usar el readonlymodificador. Las propiedades del objeto que readonlysolo se pueden asignar durante la inicialización del objeto.

Ejemplo en clases:

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.

Ejemplo en literales de objeto:

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

También vale la pena saber que el readonlymodificador es puramente una construcción mecanografiada y cuando el TS se compila a JS, la construcción no estará presente en el JS compilado. Cuando estamos modificando propiedades que son de solo lectura, el compilador de TS nos advertirá al respecto (es JS válido).

Willem van der Veen
fuente
-2

Para mí, ninguna de las respuestas anteriores funciona. Necesitaba convertir mi clase estática a enum. Me gusta esto:

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

Luego, en mi componente, agrego una nueva propiedad como se sugiere en otras respuestas

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

Luego, en la plantilla de mi componente, la uso de esta manera

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

EDITAR: Lo siento. Mi problema era diferente al de los OP. Todavía dejo esto aquí si alguien tiene el mismo problema que yo.

Janne Harju
fuente
Usar una enumeración para guardar constantes no es una buena práctica en ningún idioma.
Sangimed
Es la mejor solución para las soluciones disponibles actualmente. Sé que así es como no debería usarse enum, pero con Angular es la forma más limpia de tener constantes enlazables.
Janne Harju