TypeScript中有公共静态常量吗?我有这样一个类:

export class Library {
  public static BOOK_SHELF_NONE: string = "None";
  public static BOOK_SHELF_FULL: string = "Full";
}

在那门课上,我可以做图书馆。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的两个属性都被简单地附加到导出函数(作为其属性);因此,只要正确地访问函数本身,就应该可以访问它们。


如果你确实想要在现代浏览器中表现得更像一个静态常量值(因为它不能被其他代码更改),你可以向Library类添加一个get only访问器(这只适用于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";
}

语法更简单,也更明显。但是,编译器阻止的是更改,而不是运行时(与第一个示例不同,在第一个示例中,根本不允许更改,如所示)。


谢谢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!!!");
}

同时,这个可以通过装饰器和object。freeze或object。defineproperty结合来解决,我用的是这个,这比使用大量getter要漂亮一些。你可以复制/粘贴这个直接TS游乐场看到它在行动。-有两个选择


将单个字段设置为“final”

下面的装饰器将带注释的静态和非静态字段转换为“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
        });
    }
}

除了上面的装饰器,还有一个严格版本的this,当有人试图用"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."

您可以使用getter,这样您的属性将是只读的。 例子:

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);
    }
}

你可以使用命名空间,像这样:

export namespace Library {
    export const BOOK_SHELF_NONE: string = 'NONE';
}

然后你可以从其他地方导入它:

import {Library} from './Library';
console.log(Library.BOOK_SHELF_NONE);

如果你需要一个类,也可以将它包含在命名空间中:


只需要在你的类中使用export变量和import变量

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);