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});
}
}
預設設定使它為唯讀,但請查閱文件以了解更多細節。
