public static const in TypeScript
есть ли такая вещь, как публичные статические константы в TypeScript? У меня есть класс, который выглядит так:
export class Library {
public static BOOK_SHELF_NONE: string = "None";
public static BOOK_SHELF_FULL: string = "Full";
}
в этом классе, я могу сделать Library.BOOK_SHELF_NONE и tsc не жалуется. Но если я попытаюсь использовать библиотеку классов в другом месте и попытаюсь сделать то же самое, она не распознает ее.
8 ответов:
вот в чем этот фрагмент TS скомпилирован (через TS Playground):
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просто присоединяются к экспортируемой функции (как ее свойства); поэтому они должны быть доступны до тех пор, пока вы правильно обращаетесь к самой функции.
если вы хотите что-то, что вело себя больше как статическое постоянное значение в современных браузерах (в том, что оно не может быть изменено другим кодом), вы можете добавить
getтолько доступа к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, Я использую это, это немного красивее, чем использовать тонн добытчики. Вы можете скопировать / вставить это непосредственно TS Playground чтобы увидеть его в действии. - Есть два варианта
сделать отдельные поля "окончательной"
следующий декоратор преобразует как аннотированные статические, так и нестатические поля в "getter-only-properties".
Примечание: если экземпляр-переменная без начального значения аннотируется
@final, то первое присвоенное значение (независимо от того, когда) будет последним.// 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 }); } }
в качестве альтернативы декоратору выше, также была бы строгая версия этого, которая даже выдавала бы ошибку, когда кто-то пытался назначить некоторое значение в поле
"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!)
следующее решение также работает с 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!!!"); }
просто "экспорт" переменной и "импорт" в вашем классе
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); } }
Comments