TypeScriptのpublic static const


186

TypeScriptのパブリック静的定数などはありますか?私は次のようなクラスを持っています:

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

そのクラスでは、私はできるしLibrary.BOOK_SHELF_NONE、tscは文句を言わない。しかし、他の場所でクラスライブラリを使用しようとして、同じことを行おうとすると、認識されません。


1
他の場所でそのクラスを使用する例を示すことができますか?
— raina77ow 14

@ raina77owコードの使用方法を追加し始めたとき、名前空間のせいでtscが不平を言っていたことがわかりました。あなたがそれを答えとして入れたいなら、あなたが私を見つける手助けをしたので、私はそれを完了としてマークすることができます。自分の質問に答えるのはあまり好きではありません。
— Crystal 14

ああ、それが原因だった。)私が助けてくれてうれしいです。コンパイル結果を示す回答を追加します。
— raina77ow

1
私はまた、追加のだreadonlyあなたはそれらのフィールドを再割り当てしようとした場合の活字体はあなたに警告することを確認するために:public static readonly BOOK_SHELF_FULL
— ジャンMolak

回答:


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

ご覧のとおり、として定義された両方のプロパティpublic staticは、エクスポートされた関数に(そのプロパティとして)単にアタッチされています。したがって、関数自体に適切にアクセスする限り、それらにアクセスできる必要があります。


430

最新のブラウザーで静的定数値のように動作するもの(他のコードで変更できないため)が必要な場合は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";
}

構文は少しシンプルでわかりやすいです。ただし、コンパイラーは実行時ではなく変更を防止します(最初の例とは異なり、変更がまったく許可されません)。


26
これはとても良い答えです。そのおかげで私のコーディングは今より幸せです。
— ゴンゾフィッシュ2015

7
ただし、このソリューションには欠点があります。たとえば、これらの動的な値を型の制約として使用することはできません。たとえば、type MyType: Library.BOOK_SHELF_NONE | Library.BOOK_SHELF_FULL;
— Kostiantyn Kolesnichenko

2
@AdrianMoisa-新しい質問をしてください。
— WiredPrairie 2016

2
@hex新しい質問をしてください。
— WiredPrairie 2016年

1
列挙型はどうですか?
— curious95 2018

40

次のように、名前空間を使用して行うことができます。

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

次に、それを他のどこからでもインポートできます。

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

そこにクラスが必要な場合は、名前空間に含めます。 export class Book {...}


2
オブジェクトの初期化で定数を使用している場合、それらは認識されないようです。たとえば{ type: Library.BOOK_SHELF_NONE }、名前空間にと呼ばれるエクスポートがないと考えているようBOOK_SHELF_NONEです。ただし、ローカル変数に参照を設定しただけでは、問題は解決されます。TS 2.2
— クラッシュ

13

一方で、これはとの組み合わせでデコレータを通じて解決することができるObject.freezeかObject.defineProperty、私はこれを使用している、それはゲッターのトンを使用するよりも少しきれいです。これを直接TSプレイグラウンドにコピー/貼り付けて、実際の動作を確認できます。-2つのオプションがあります


個々のフィールドを「最終」にする

次のデコレータは、注釈付きの静的フィールドと非静的フィールドの両方を「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
    });
}

すべての静的フィールドを「最終」にします

考えられる欠点:これは、そのクラスのすべてのstaticに対してのみ機能するか、どれにも機能しませんが、特定のstaticには適用できません。

/**
* 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."

これは最もクリーンなアプローチだと思います。ありがとう!
— Thibs

一つの少量の添加は:if (!value)である必要がありif (value === undefined)、静的な値があることようにします""か0。
— Leon Adler

6

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

2

次のソリューションも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!!!");
}

これは本当にすばらしいですが、それを使用して2つ以上の値を定義している場合(他の言語のEnumのように)、すべての値を個別にインポートすることはできません。これは本当に面倒になるかもしれません!
— Corey Larson

100%同意。それらを名前空間化できるかもしれませんが、私はそれを調べていません。"./Constants.ts"から{ArrayConstants}をインポートしてから、ArrayConstants.NotFoundのようなことを行うことができます。時間があるときはもっと遊んでいなければならない。
— Andrew

ええ、名前空間を使用して、値を個別に使用するのを避けることができます。ここで自分の答えを読んでください。
— Ivan Castellanos

0

単に '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);

0

ゲッターを使用して、プロパティが読み取り専用になるようにすることができます。例:

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

この定数は書き込み可能であることが期待される何が:let a = new MyClass(); a.STATUSES.level1 = 'not level1'; let plainWrong = new MyClass().STATUSES.level1; // 'not level1'
— レオン・アドラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.