TypeScript中的public static const

Cry*_*tal 175 typescript

在TypeScript中是否存在公共静态常量?我有一个类看起来像:

export class Library {
  public static BOOK_SHELF_NONE: string = "None";
  public static BOOK_SHELF_FULL: string = "Full";
}
Run Code Online (Sandbox Code Playgroud)

在那个班级,我可以做Library.BOOK_SHELF_NONE,而且tsc不会抱怨.但是如果我尝试在其他地方使用类库,并尝试做同样的事情,它就无法识别它.

Wir*_*rie 406

如果你确实想要在现代浏览器中表现得更像静态常量值的东西(因为它不能被其他代码更改),你可以getLibrary类中添加一个唯一的访问器(这只适用于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);
Run Code Online (Sandbox Code Playgroud)

如果运行它,您将看到将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";
}
Run Code Online (Sandbox Code Playgroud)

语法更简单,更明显.但是,编译器会阻止更改而不是运行时(与第一个示例中的情况不同,根据演示,根本不允许更改).

  • 这是一个很好的答案.因为它,我的编码现在更快乐了. (24认同)
  • 这个解决方案有一个缺点 - 你不能将这些*dynamic*值用作类型约束,例如:`type MyType:Library.BOOK_SHELF_NONE | Library.BOOK_SHELF_FULL;` (6认同)
  • @AdrianMoisa - 请问一个新问题. (2认同)
  • @ hex-请问一个新问题. (2认同)

Iva*_*nos 40

您可以使用名称空间来执行此操作,如下所示:

export namespace Library {
    export const BOOK_SHELF_NONE: string = 'NONE';
}
Run Code Online (Sandbox Code Playgroud)

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

import {Library} from './Library';
console.log(Library.BOOK_SHELF_NONE);
Run Code Online (Sandbox Code Playgroud)

如果你需要一个类,那么它也包含在命名空间中: export class Book {...}

  • 如果我在对象的初始化中使用常量,它们似乎不会被识别.例如:`{type:Library.BOOK_SHELF_NONE}`似乎认为名称空间没有名为`BOOK_SHELF_NONE`的导出.但是,如果我只是使用引用设置局部变量,它可以很好地解决它.TS 2.2 (2认同)

rai*_*7ow 26

这是这个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;
});
Run Code Online (Sandbox Code Playgroud)

如您所见,定义为的两个属性public static都只是附加到导出的函数(作为其属性); 因此,只要您正确访问该功能本身,它们就应该是可访问的.


ols*_*lsn 13

同时,这可以通过装饰器结合使用来解决,Object.freeze或者Object.defineProperty,我使用它,它比使用大量的吸气剂更漂亮.您可以直接复制/粘贴此TS Playground以查看其运行情况. - 有两种选择


使个别领域"最终"

以下装饰器将带注释的静态和非静态字段转换为"仅getter-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.
Run Code Online (Sandbox Code Playgroud)

装饰者:确保在代码中包含这个!

/**
* 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
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

作为上面装饰器的替代品,也会有一个严格的版本,当有人试图通过"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
    });
}
Run Code Online (Sandbox Code Playgroud)

让每个静态领域"最终"

可能的下行:这仅适用于该类的所有静态或无,但不能应用于特定的静态.

/**
* 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);
}
Run Code Online (Sandbox Code Playgroud)
// 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."
Run Code Online (Sandbox Code Playgroud)


And*_*rew 6

谢谢WiredPrairie!

只是为了扩展你的答案,这里是一个定义常量类的完整例子.

// CYConstants.ts

class CYConstants {
    public static get NOT_FOUND(): number    { return -1; }
    public static get EMPTY_STRING(): string { return ""; }
}

export = CYConstants;
Run Code Online (Sandbox Code Playgroud)

使用

// main.ts

import CYConstants = require("./CYConstants");

console.log(CYConstants.NOT_FOUND);    // Prints -1
console.log(CYConstants.EMPTY_STRING); // Prints "" (Nothing!)
Run Code Online (Sandbox Code Playgroud)