Como implementar constantes de classe em texto datilografado?

430

No TypeScript, a constpalavra - chave não pode ser usada para declarar propriedades da classe. Fazer isso causa um erro no compilador com "Um membro da classe não pode ter a palavra-chave 'const'".

Sinto-me na necessidade de indicar claramente no código que uma propriedade não deve ser alterada. Quero que o IDE ou o compilador tenha erro se tentar atribuir um novo valor à propriedade depois que ela for declarada. Como vocês conseguem isso?

Atualmente, estou usando uma propriedade somente leitura, mas sou novo no Typescript (e JavaScript) e me pergunto se existe uma maneira melhor:

get MY_CONSTANT():number {return 10};

Estou usando o texto datilografado 1.8. Sugestões?

PS: Agora estou usando o texto datilografado 2.0.3, então aceitei a resposta de David

Suco de besouro
fonte

Respostas:

652

O TypeScript 2.0 possui o readonlymodificador :

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

Não é exatamente uma constante, porque permite a atribuição no construtor, mas isso provavelmente não é grande coisa.

Solução alternativa

Uma alternativa é usar a staticpalavra-chave com 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

Isso tem o benefício de não ser atribuível no construtor e existir apenas em um local.

David Sherret
fonte
31
Para acessar as propriedades de fora da classe, você precisará adicionar a exportpalavra - chave antes classe public staticantes da readonlypalavra - chave. Veja aqui: stackoverflow.com/a/22993349
cbros2008
Questão. Por que você precisa do nome da classe para usar essa propriedade readOnly dentro da própria classe? 'MyClass.myReadonlyProperty'
Saiyaff Farouk 23/03
@SaiyaffFarouk Se entendi sua pergunta, a resposta é que propriedades estáticas existem como parte da classe, não em uma instância da classe. Portanto, você os acessa usando o nome da classe e não uma variável que contém uma instância da classe.
precisa saber é o seguinte
1
Os export(módulos externos) e a publicpalavra - chave não estão relacionados a essa pergunta / resposta, mas no tópico explicitação, pessoalmente, acho extremamente fácil dizer que um membro é público quando a palavra-chave não existe. Eu não me importo com isso por esse motivo e porque adiciona mais ruído e é desnecessário digitar. Também torna os membros públicos mais distintos daqueles marcados como privateou protected. De qualquer forma, apenas a minha opinião :)
David Sherret
E as aulas anônimas? Alguma idéia de como acessar static readonly myReadOnlyPropertyquando a classe é declarada export default class { ... }? Tentou this.myVar, self.myVar, estático, padrão ... não funciona ... (EDIT: default.myVar parece ser a solução, mas eu estou recebendo um erro de tipo)
Alcalyn
67

As constantes podem ser declaradas fora das classes e usadas dentro da sua classe. Caso contrário, a getpropriedade é uma boa solução alternativa

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
j3ff
fonte
6
Obrigado; Estou preocupado com essa implementação porque ela não é portátil (no modelo, a constante não faz parte da classe) e vaza informações para um escopo maior, mas tem a vantagem de ser uma constante real, então eu venci ' Não é possível alterá-lo sem disparar alarmes.
BeetleJuice
1
Eu entendo a preocupação e acho que o uso de getpropriedade muito apropriado no seu caso
j3ff
3
Por angular.io/docs/ts/latest/guide/style-guide.html , use camel caase em vez de maiúsculas. Letras maiúsculas para constantes não são recomendadas.
Vadim Kirilchuk 5/03
12
Styleguide angular, não typescript Styleguide .. pergunta foi sobre typescript especificamente
VeldMuijz
4
@ Esko Eu acredito que no texto datilografado a const é limitada ao arquivo porque cada arquivo é um módulo. Para torná-lo acessível fora, você precisará declará-lo export conste importá-lo de outro arquivo. Seria muito fácil testar, no entanto. Apenas declare um constem um arquivo e tente usá-lo em outro sem exportar / importar ou usá-lo no console do navegador.
precisa saber é o seguinte
42

Você pode marcar propriedades com readonlymodificador na sua declaração:

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

@see livro TypeScript Deep Dive - Readonly

am0wa
fonte
11

Angular 2 Fornece um recurso muito interessante chamado Constantes Opacas. Crie uma classe e defina todas as constantes lá 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/"    
};

Injete-o em provedores em app.module.ts

Você poderá usá-lo em todos os componentes.

EDIT para Angular 4:

Para o Angular 4, o novo conceito é Token de injeção e o token opaco foi preterido no Angular 4.

Token de injeção Adiciona funcionalidades sobre os Tokens opacos, permite anexar informações de tipo no token via genéricos TypeScript, além de tokens de injeção, elimina a necessidade de adicionar @Inject

Código de exemplo

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 tokens de injeção

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

Os tokens de injeção são projetados logicamente em cima de tokens opacos e os tokens opacos são descontinuados no Angular 4.

Parth Ghiya
fonte
6
mais um. Angular é tão estável quanto um adolescente de 13 anos. eles ficam com os recursos obsoletos alguns meses após serem liberados. mesquinho.
Stavm
1
menos um. Esta questão não tem nada a ver com Angular. Ele está solicitando uma solução TypeScript.
Ben Nieting
4

Use o modificador readOnly com a constante que precisa declarar ou se pode declarar uma constante fora da classe e use-a especificamente apenas na classe necessária, usando o operador get.

Krishna Ganeriwal
fonte
1

Para isso, você pode usar o readonlymodificador. As propriedades do objeto que são readonlyapenas podem ser atribuídas durante a inicialização do objeto.

Exemplo nas classes:

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.

Exemplo em literais 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

Também vale a pena saber que o readonlymodificador é puramente uma construção datilografada e quando o TS for compilado para JS, a construção não estará presente no JS compilado. Quando estamos modificando propriedades que são somente leitura, o compilador TS nos avisa sobre isso (é JS válido).

Willem van der Veen
fonte
-2

Para mim, nenhuma das respostas anteriores funciona. Eu precisava converter minha classe estática em enum. Como isso:

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

Então, no meu componente, adiciono nova propriedade, conforme sugerido em outras respostas

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

Em seguida, no modelo do meu componente, eu o uso dessa maneira

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

EDIT: Desculpe. Meu problema era diferente do do OP. Ainda deixo isso aqui se alguém tiver o mesmo problema que eu.

Janne Harju
fonte
Usar um enum para salvar constantes não é uma boa prática em nenhum idioma.
Sangimed 06/04
É a melhor solução para soluções disponíveis atualmente. Eu sei que é como enum não deve ser usado, mas com Angular é a maneira mais limpa de ter constantes vinculáveis.
Janne Harju