TypeScript中的public static const
在TypeScript中是否存在公共静态常量? 我有一个类,看起来像:
export class Library { public static BOOK_SHELF_NONE: string = "None"; public static BOOK_SHELF_FULL: string = "Full"; }
在那个课上,我可以做Library.BOOK_SHELF_NONE
和tsc不会抱怨。 但是,如果我尝试在其他地方使用类库,并尝试做同样的事情,它不认识它。
这是什么TS代码片段编译成(通过TS游乐场 ):
define(["require", "exports"], function(require, exports) { var Library = (function () { function Library() { } Library.BOOK_SHELF_NONE = "None"; Library.BOOK_SHELF_FULL = "Full"; return Library; })(); exports.Library = Library; });
正如你看到的,这两个定义为public static
属性只是附加到导出的函数(作为它的属性)。 因此,只要您正确访问函数本身,就应该可以访问它们。
如果你确实想要在现代浏览器中performance得更像是一个静态的常量值(因为它不能被其他代码所改变),你可以在Library
类中添加一个只读的访问器(这只适用于ES5 +浏览器,的NodeJS):
export class Library { public static get BOOK_SHELF_NONE():string { return "None"; } public static get BOOK_SHELF_FULL():string { return "Full"; } } var x = Library.BOOK_SHELF_NONE; console.log(x); Library.BOOK_SHELF_NONE = "Not Full"; x = Library.BOOK_SHELF_NONE; console.log(x);
如果您运行它,您将看到如何尝试将BOOK_SHELF_NONE
属性设置为新值不起作用。
2.0
在TypeScript 2.0中,你可以使用readonly
来获得非常相似的结果:
export class Library { public static readonly BOOK_SHELF_NONE = "None"; public static readonly BOOK_SHELF_FULL = "Full"; }
语法有点简单和明显。 但是,编译器可以防止更改,而不是运行时间(不像第一个示例中那样,根本不允许更改)。
你可以使用命名空间来做到这一点:
export namespace Library { export const BOOK_SHELF_NONE: string = 'NONE'; }
那么你可以从其他地方导入它:
import {Library} from './Library'; console.log(Library.BOOK_SHELF_NONE);
如果您需要一个类,并将其包含在命名空间中: export class Book {...}
同时这可以通过装饰器与Object.freeze
或Object.defineProperty
结合来解决,我使用这个,比使用大量的getter稍微漂亮些。 您可以直接复制/粘贴到TS Playground,以便看到它在行动。 – 有两个选项
使个别领域“最终”
下面的装饰器将注释的静态和非静态字段都转换为“getter-only-properties”。
注意 :如果没有初始值的实例variables被@final
为@final
,那么第一个赋值(不pipe何时)将是最后一个。
// example class MyClass { @final public finalProp: string = "You shall not change me!"; @final public static FINAL_FIELD: number = 75; public static NON_FINAL: string = "I am not final." } var myInstance: MyClass = new MyClass(); myInstance.finalProp = "Was I changed?"; MyClass.FINAL_FIELD = 123; MyClass.NON_FINAL = "I was changed."; console.log(myInstance.finalProp); // => You shall not change me! console.log(MyClass.FINAL_FIELD); // => 75 console.log(MyClass.NON_FINAL); // => I was changed.
装饰者:确保你包含在你的代码!
/** * Turns static and non-static fields into getter-only, and therefor renders them "final". * To use simply annotate the static or non-static field with: @final */ function final(target: any, propertyKey: string) { const value: any = target[propertyKey]; // if it currently has no value, then wait for the first setter-call // usually the case with non-static fields if (!value) { Object.defineProperty(target, propertyKey, { set: function (value: any) { Object.defineProperty(this, propertyKey, { get: function () { return value; }, enumerable: true, configurable: false }); }, enumerable: true, configurable: true }); } else { // else, set it immediatly Object.defineProperty(target, propertyKey, { get: function () { return value; }, enumerable: true }); } }
作为上面装饰器的替代scheme,还会有一个严格的版本,当有人试图用"use strict";
来赋值字段时,甚至会抛出一个错误"use strict";
被设置。 (虽然这只是静态部分)
/** * Turns static fields into getter-only, and therefor renders them "final". * Also throws an error in strict mode if the value is tried to be touched. * To use simply annotate the static field with: @strictFinal */ function strictFinal(target: any, propertyKey: string) { Object.defineProperty(target, propertyKey, { value: target[propertyKey], writable: false, enumerable: true }); }
使每个静态字段“最终”
可能的下行:这将只适用于该类的所有静态或无效,但不能应用于特定的静态。
/** * Freezes the annotated class, making every static 'final'. * Usage: * @StaticsFinal * class MyClass { * public static SOME_STATIC: string = "SOME_STATIC"; * //... * } */ function StaticsFinal(target: any) { Object.freeze(target); }
// Usage here @StaticsFinal class FreezeMe { public static FROZEN_STATIC: string = "I am frozen"; } class EditMyStuff { public static NON_FROZEN_STATIC: string = "I am frozen"; } // Test here FreezeMe.FROZEN_STATIC = "I am not frozen."; EditMyStuff.NON_FROZEN_STATIC = "I am not frozen."; console.log(FreezeMe.FROZEN_STATIC); // => "I am frozen." console.log(EditMyStuff.NON_FROZEN_STATIC); // => "I am not frozen."
谢谢你WiredPrairie!
稍微扩展一下你的答案,下面是一个定义常量类的完整例子。
// CYConstants.ts class CYConstants { public static get NOT_FOUND(): number { return -1; } public static get EMPTY_STRING(): string { return ""; } } export = CYConstants;
使用
// main.ts import CYConstants = require("./CYConstants"); console.log(CYConstants.NOT_FOUND); // Prints -1 console.log(CYConstants.EMPTY_STRING); // Prints "" (Nothing!)
以下解决scheme也适用于TS 1.7.5。
// Constancts.ts export const kNotFoundInArray = -1; export const AppConnectionError = new Error("The application was unable to connect!"); export const ReallySafeExtensions = ["exe", "virus", "1337h4x"];
使用:
// Main.ts import {ReallySafeExtensions, kNotFoundInArray} from "./Constants"; if (ReallySafeExtensions.indexOf("png") === kNotFoundInArray) { console.log("PNG's are really unsafe!!!"); }
只需简单地在你的课堂上“导出”variables和“导入”即可
export var GOOGLE_API_URL = 'https://www.googleapis.com/admin/directory/v1'; // default err string message export var errStringMsg = 'Something went wrong';
现在使用它,
import appConstants = require('../core/AppSettings'); console.log(appConstants.errStringMsg); console.log(appConstants.GOOGLE_API_URL);
你可以使用吸气剂,这样你的财产将只能读取。 例:
export class MyClass { private _LEVELS = { level1: "level1", level2: "level2", level2: "level2" }; public get STATUSES() { return this._LEVELS; } }
用于另一个类:
import { MyClass } from "myclasspath"; class AnotherClass { private myClass = new MyClass(); tryLevel() { console.log(this.myClass.STATUSES.level1); } }