網站搜尋

TypeScript - 如何實作類別常數?


在 TypeScript 中,const 關鍵字不能用來宣告類的屬性。這麼做會導致編譯器出現錯誤訊息:「類成員不能有 'const' 關鍵字。」

我發現自己需要在程式碼中明確地指出某個屬性不應該被更改。我希望如果我嘗試在屬性宣告後賦予新值,IDE 或編譯器會報錯。你們是如何達到這個目的的?

我目前正在使用只讀屬性,但我想知道是否有更好的方法:

get MY_CONSTANT():number {return 10};

我正在使用 TypeScript 1.8。有什麼建議嗎?

附註:我現在使用的是 TypeScript 2.0.3,所以我已經接受了 David 的答案

答案#1

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

這的好處是無法在建構函數中指定,只存在於一個地方。

答案#2

常數可以在類別之外宣告,並在你的類別中使用。否則,get 屬性是一個不錯的替代方法

const MY_CONSTANT: string = "wazzup";

export class MyClass {

    public myFunction() {

        alert(MY_CONSTANT);
    }
}

答案#3

你可以在宣告中使用 readonly 修飾符標記屬性:

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

@see TypeScript 深入探索 書籍 - 只讀

答案#4

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 中注入它到 providers

你將能夠在每個組件中使用它。

為 Angular 4 編輯:

對於 Angular 4,新的概念是 Injection Token,而 Opaque token 在 Angular 4 中已被棄用。

注入令牌在不透明令牌的基礎上增加功能,它允許通過 TypeScript 泛型在令牌上附加類型信息,此外注入令牌還消除了添加 @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!
    ]
  }
]

注入標記在邏輯上是建立在不透明標記之上的,而不透明標記在 Angular 4 中已被棄用。

答案#5

所有帶有 readonly 的回覆僅適用於純 TS 環境——如果它將來要被做成一個庫,這其實並不能真正阻止任何事情,它只是為 TS 編譯器本身提供警告。

Static 也是不正確的——那是將方法添加到類別,而不是類別的 實例——所以你需要直接處理它。

有幾種方法可以管理這個,但純粹的 TS 方式是使用 getter——就像你已經做的那樣。

另一種方法是將其設為 readonly,但接著使用 Object.defineProperty 來鎖定它——這幾乎與通過 getter 所做的事情相同,但你可以鎖定它以擁有一個值,而不是使用方法來獲取它。

class MyClass {
    MY_CONSTANT = 10;

    constructor() {
        Object.defineProperty(this, "MY_CONSTANT", {value: this.MY_CONSTANT});
    }
}

預設設定使它為唯讀,但請查閱文件以了解更多細節。