Как реализовать константы класса в машинописи?

430

В TypeScript constключевое слово нельзя использовать для объявления свойств класса. Это приводит к ошибке компилятора: «Член класса не может иметь ключевое слово« const ».»

Мне нужно четко указать в коде, что свойство не должно быть изменено. Я хочу, чтобы среда IDE или компилятор выдавали ошибку, если я пытаюсь присвоить новое значение свойству после его объявления. Как вы, ребята, добились этого?

В настоящее время я использую свойство только для чтения, но я новичок в Typescript (и JavaScript) и задаюсь вопросом, есть ли лучший способ:

get MY_CONSTANT():number {return 10};

Я использую машинопись 1.8. Предложения?

PS: сейчас я использую машинопись 2.0.3, поэтому я принял ответ Дэвида

Сок жука
источник

Ответы:

653

TypeScript 2.0 имеет readonlyмодификатор :

class MyClass {
    readonly myReadOnlyProperty = 1;

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

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

Это не совсем константа, потому что она позволяет присваивать в конструкторе, но это, скорее всего, не имеет большого значения.

Альтернативное решение

Альтернативой является использование staticключевого слова с 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

Преимущество этого состоит в том, что он не может быть назначен в конструкторе и существует только в одном месте.

Дэвид Шеррет
источник
32
Чтобы получить доступ к свойствам вне класса, вам нужно добавить exportключевое слово classкак до, так и public staticперед readonlyключевым словом. Смотрите здесь: stackoverflow.com/a/22993349
cbros2008
Вопрос. Не было понятно, зачем вам нужно имя класса, чтобы использовать это свойство readOnly внутри самого класса? 'MyClass.myReadonlyProperty'
Сайяфф Фарук,
@SaiyaffFarouk Если я понимаю ваш вопрос, ответ заключается в том, что статические свойства существуют как часть класса, а не как экземпляр класса. Таким образом, вы обращаетесь к ним, используя имя класса, а не переменную, которая содержит экземпляр класса.
JeffryHouser
1
В export(внешние модули) и publicключевое слово не имеют никакого отношения к этому вопрос / ответ, но на тему эксплицитности, я лично считаю , это очень легко сказать , что член является публичным , когда ключевое слово не существует. Я не беспокоюсь об этом по этой причине и потому, что это добавляет больше шума и бесполезно печатать. Это также делает общественных участников более отличными от тех, которые отмечены как privateили protected. Во всяком случае, только мое мнение :)
Дэвид Шеррет
А как насчет анонимных классов? Любые идеи о том, как получить доступ, static readonly myReadOnlyPropertyкогда класс объявлен с export default class { ... }? Пробовал this.myVar, self.myVar, static, default ... не работает ... (EDIT: default.myVar, кажется, решение, но я получаю ошибку типа)
Alcalyn
67

Константы могут быть объявлены вне классов и использоваться внутри вашего класса. В противном случае getэто хороший обходной путь

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}
j3ff
источник
6
Спасибо; Я беспокоюсь об этой реализации, потому что она не переносима (в модели константа на самом деле не является частью класса) и она пропускает информацию в большую область, но у нее есть преимущество в том, что она является настоящей константой, поэтому я выиграл » не сможет изменить его, не поднимая тревогу.
BeetleJuice
1
Я понимаю проблему и считаю использование getсобственности очень уместным в вашем случае
j3ff
3
Согласно angular.io/docs/ts/latest/guide/style-guide.html, используйте заглавные буквы вместо прописных. Верхний регистр для констант не рекомендуется.
Вадим Кирилчук
12
Угловое руководство по стилю, а не руководство по TypeScript. Вопрос
касался
4
@Esko Я считаю, что в машинописи const ограничен файлом, потому что каждый файл является модулем. Чтобы сделать его доступным снаружи, вам необходимо объявить его с помощью export constи затем импортировать его из другого файла. Было бы довольно легко проверить, хотя. Просто объявите constв одном файле и попробуйте использовать его в другом без экспорта / импорта или использовать его из консоли браузера.
BeetleJuice
42

Вы можете пометить свойства с помощью readonlyмодификатора в вашем объявлении:

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

@see машинопись Deep Dive книга - ReadOnly

am0wa
источник
11

Angular 2 Обеспечивает очень хорошую функцию, называемую непрозрачными константами. Создайте класс и определите все константы там, используя непрозрачные константы.

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

Внедрить его в провайдеров в app.module.ts

Вы сможете использовать его для всех компонентов.

РЕДАКТИРОВАТЬ для Angular 4:

Для Angular 4 новой концепцией является Injection Token, а Opaque token устарела в Angular 4.

Injection Token Добавляет функциональные возможности поверх непрозрачных токенов, позволяет прикреплять информацию о типе к токену с помощью обобщений TypeScript, а также токенов Injection, устраняет необходимость добавления @Inject

Пример кода

Angular 2 с использованием непрозрачных токенов

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 Использование токенов

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

Токены инъекции логически разработаны поверх жетонов Opaque, а жетоны Opaque устарели в Angular 4.

Парт Гия
источник
6
плюс один. Angular так же стабилен, как и 13-летний подросток. через несколько месяцев после их выпуска они получают устаревшие функции. мелкая.
Став
1
минус один. Этот вопрос не имеет никакого отношения к Angular. Он запрашивает решение TypeScript.
Бен Nieting
4

Либо используйте модификатор readOnly с константой, которую необходимо объявить, либо можно объявить константу вне класса и использовать ее специально только в требуемом классе, используя оператор get.

Кришна Ганеривал
источник
1

Для этого вы можете использовать readonlyмодификатор. Свойства объекта, которые readonlyмогут быть назначены только во время инициализации объекта.

Пример в классах:

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.

Пример в литералах объекта:

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

Также стоит знать, что readonlyмодификатор является чисто структурой машинописного текста, и когда TS скомпилирован в JS, эта конструкция не будет присутствовать в скомпилированном JS. Когда мы изменяем свойства, которые доступны только для чтения, компилятор TS предупредит нас об этом (это действительно JS).

Виллем ван дер Веен
источник
-2

Для меня ни один из более ранних ответов не работает. Мне нужно было преобразовать мой статический класс в enum. Нравится:

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

Затем в моем компоненте я добавляю новое свойство, как предлагается в других ответах

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

Затем в шаблоне моего компонента я использую его таким образом

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

РЕДАКТИРОВАТЬ: Извините. Моя проблема отличалась от ОП. Я все еще оставляю это здесь, если у кого-то есть та же проблема, что и у меня.

Янне Харью
источник
Использование перечисления для сохранения констант не является хорошей практикой ни на одном языке.
Сангимед
Это лучшее решение для решений, доступных в настоящее время. Я знаю, что enum не следует использовать, но с Angular это самый чистый способ иметь привязываемые константы.
Янне Харью