Як реалізувати константи класу в машинопис?


429

У TypeScript constключове слово не може використовуватися для оголошення властивостей класу. Це призводить до помилки компілятора з "Класом не може бути ключове слово" const "."

Мені здається, що потрібно чітко вказати в коді, що властивість не слід змінювати. Я хочу, щоб IDE або компілятор помилилися, якщо я спробую призначити нове значення властивості, як тільки воно було оголошено. Як ви, хлопці, цього досягаєте?

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

get MY_CONSTANT():number {return 10};

Я використовую машинопис 1.8. Пропозиції?

PS: Зараз я використовую typecript 2.0.3, тому я прийняв відповідь Девіда

Відповіді:


651

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

Це має перевагу в тому, що він не може бути призначений конструктору і існує лише в одному місці.


31
Щоб отримати доступ до властивостей поза класом, вам потрібно буде додати exportключове слово раніше class, а також public staticперед readonlyключовим словом. Дивіться тут: stackoverflow.com/a/22993349
cbros2008

Питання. Було зрозуміло, чому вам потрібно ім'я класу, щоб використовувати властивість readOnly всередині самого класу? 'MyClass.myReadonlyProperty'
Saiyaff Farouk

@SaiyaffFarouk Якщо я розумію ваше запитання, відповідь полягає в тому, що статичні властивості існують як частина класу, а не в екземплярі класу. Отже, ви отримуєте доступ до них за допомогою імені класу, а не змінної, яка містить екземпляр класу.
JeffryHouser

1
В export(зовнішні модулі) і publicключове слово НЕ мають ніякого відношення до цього питання / відповідь, але на тему експліцитно, я особисто вважаю , це дуже легко сказати , що член є публічним , коли ключове слово не існує. Я не турбуюсь з цієї причини, тому що це додає більше шуму і не потрібно вводити текст. Це також робить членів громадськості більш відмінними від тих, що позначені як privateабо protected. У всякому разі, тільки моя думка :)
Девід Шеррет

А як щодо анонімних занять? Будь-які ідеї, як отримати доступ static readonly myReadOnlyPropertyпри оголошенні класу export default class { ... }? Спробував це.myVar, self.myVar, статичний, за замовчуванням ... не працює ... (EDIT: default.myVar, здається, рішення, але я отримую помилку типу)
Алкалін

67

Константи можна декларувати поза класами та використовувати у вашому класі. В іншому випадку getвласність є хорошим способом вирішення

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}

6
Дякую; Я переживаю за цю реалізацію, оскільки вона не є портативною (у моделі константа насправді не є частиною класу), і вона просочує інформацію в більшу сферу, але вона має перевагу бути реальною константою, тому я виграв ' не зможете змінити його, не піднімаючи дзвони.
Жук-сік

1
Я розумію занепокоєння, і вважаю використання getмайна у Вашому випадку дуже доречним
j3ff

3
Для angular.io/docs/ts/latest/guide/style-guide.html будь ласка, використовуйте верблюжої кази замість верхнього регістру. Верхній регістр для констант не рекомендується.
Вадим Кирильчук

12
Кутове стилеводство, а не TypeScript styleguide .. Питання стосувалося саме TypeScript
VeldMuijz

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 Книга заглибленого заглиблення TypeScript - Readonly


11

Кутовий 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

Ви зможете використовувати його для всіх компонентів.

EDIT для кутових 4:

Для Angular 4 нова концепція - Injection Token & Opaque маркер застаріла в Angular 4.

Інжекційний маркер Додає функціональні можливості поверх непрозорих жетонів, він дозволяє приєднувати інформацію про тип до маркера через generics TypeScript, а також маркери ін'єкції, усуває необхідність додавання @Inject

Приклад коду

Кутовий 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
    ]
  }
]

Кутовий 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 застарілі в куті 4.


6
плюс один. Кутовий такий же стійкий, як і 13-річний підліток. вони отримують застарілі функції через кілька місяців після випуску. дріб'язковий
Ставм

1
мінус один. Це питання не має нічого спільного з Angular. Він запитує рішення TypeScript.
Бен Нітінг

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

Для мене жодна попередня відповідь не працює. Мені потрібно було перетворити свій статичний клас в перерахунок. Подобається це:

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

Потім у свій компонент я додаю нову властивість, як пропонується в інших відповідях

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

Потім у шаблоні мого компонента я використовую його таким чином

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

EDIT: Вибачте. Моя проблема була іншою, ніж ОП. Я все одно залишаю це тут, якщо у когось інших проблем є, ніж у мене.


Використання enum для економії констант не є хорошою практикою на будь-якій мові.
Сангімед

Це найкраще рішення для рішень, доступних на даний момент. Я знаю, що не слід використовувати enum, але з Angular це найпростіший спосіб мати константи, що зміщуються.
Janne Harju
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.