TypeScript静的クラス


145

C#に似た構文が好きなので、従来のJSからTypeScriptに移行したいと思いました。私の問題は、TypeScriptで静的クラスを宣言する方法が見つからないことです。

C#では、静的クラスを使用して変数とメソッドを編成し、オブジェクトをインスタンス化することなく、名前付きクラスにまとめます。バニラJSでは、私は単純なJSオブジェクトでこれを行っていました:

var myStaticClass = {
    property: 10,
    method: function(){}
}

TypeScriptでは、私はむしろC-sharpyアプローチを採用したいと思いますが、静的クラスはTSに存在しないようです。この問題の適切な解決策は何ですか?

回答:


166

TypeScriptはC#ではないため、TypeScriptでのC#の同じ概念を必ずしも期待するべきではありません。問題は、なぜ静的クラスが必要なのかということです。

C#では、静的クラスは単にサブクラス化できないクラスであり、静的メソッドのみを含める必要があります。C#では、クラスの外部で関数を定義することはできません。ただし、TypeScriptではこれが可能です。

関数/メソッドを名前空間(つまり、グローバルではない)に配置する方法を探している場合は、TypeScriptのモジュールの使用を検討できます。

module M {
    var s = "hello";
    export function f() {
        return s;
    }
}

そのため、外部ではMf()にアクセスできますが、sにはアクセスできず、モジュールを拡張できません。

詳細については、TypeScript 仕様を参照してください。


したがって、モジュールは静的メソッドを持つことができますが、クラスは持つことができませんか?ただし、モジュールに静的データを含めることはできません。何もインスタンス化せずにデータやコードをラップすることは、JSほど便利ではありません。
dcsan 2015

あなたが含める必要がありますことを含めることが有益であるかもしれない.jsあなたにhtml。そうするためにAngular 2、あなたはおそらく使用しているSystem...やるso'd System.import("Folder/M");(またはパスがコンパイルにあるものは何でも.jsファイル)の前にbootstrap import
Serjセーガン

11
これは非推奨です。また、tslintはモジュールと名前空間に対してそれを行うことをもう許可しません。こちらをお読みください:palantir.github.io/tslint/rules/no-namespace
Florian Leitgeb

静的クラスを使用するユースケースがあります。現在、静的メソッドのみを含むクラスがあります。プロジェクトでは、インスタンス化できるクラスごとになんらかの構成を提供する必要があります。そのようなクラスをstaticとして宣言すると、インスタンス化されないことに気付くだけでなく、他の開発者がインスタンスメンバーをそれに追加することを回避できます。
mdarefull 2018

@florian leitgebでは、静的メソッドや抽象キーワードのみを含むクラスの場合、どのような方法が推奨されますか それはちょうど廃止思われるモジュールに比べて安っぽいようだ
wired00

181

抽象クラスは、TypeScript 1.6以降、TypeScriptの第一級の市民となっています。抽象クラスをインスタンス化することはできません。

次に例を示します。

export abstract class MyClass {         
    public static myProp = "Hello";

    public static doSomething(): string {
      return "World";
    }
}

const okay = MyClass.doSomething();

//const errors = new MyClass(); // Error

6
静的クラスを扱う場合、これが最良の応答であり、私はこれを支持します。Singleton同じクラスインスタンスの共有メモリパターン用です。また、静的クラスには定義上インスタンスがないため、クライアントが初期化しようとした場合は例外をスローする必要があります。
loretoparisi 2016

1
抽象クラスを作成できますか?
KimchiMan 2017

@KimchiMan-はい、abstractキーワードはTypeScriptでサポートされています。
フェントン2017

1
使用するために更新されましたabstract!@KimchiMan-素晴らしいアイデア!
黒曜石

3
これは、コンストラクタをプライベートとしてマークするよりも良い方法ですか?
ジョロテネフ

72

クラスの静的プロパティとメソッドの定義については、Typescript言語仕様の 8.2.1で説明されています。

class Point { 
  constructor(public x: number, public y: number) { } 
  public distance(p: Point) { 
    var dx = this.x - p.x; 
    var dy = this.y - p.y; 
    return Math.sqrt(dx * dx + dy * dy); 
  } 
  static origin = new Point(0, 0); 
  static distance(p1: Point, p2: Point) { 
    return p1.distance(p2); 
  } 
}

ここで、Point.distance()静的(または「クラス」)方法があります。


14
これは、静的メソッドの作成方法を示しています。静的クラスに関する質問には答えません(実際の質問が実際に静的メソッドに関するものでない限り)。
Marcus

18
コメントをありがとう。静的プロパティと静的メソッドを作成する方法について説明します。これらを組み合わせることで、インスタンス化を必要とせずにデータと機能を備えたクラスを作成できます。特に「静的クラス」ではありませんが、OPのJavaScriptの例で説明されている要件を満たしています。
Rob Raisch

C#には、バージョン2までは静的クラスがありませんでした。それらはインスタンス化を防ぐためだけにC#に存在します。あなたはそれをjavascriptで行うことができないのであまり意味がありません
Simon_Weaver

4
@Simon_WeaverあなたはJavaScriptで何ができないのですか?クラスがインスタンス化されないようにしますか?とにかく、許可されていないことを実行しようとするとコンパイルエラーが発生する限り、Typescriptはランタイムについてあまり気にしません。
Alex

私が意味したのは、バージョン2までは「クラスレベルで静的キーワードがなかった(つまり、クラスのインスタンスを作成できない)」ということでしたが、もう一度読むと、私のコメントは、とにかくポイント。OPはクラス全体の「静的キーワード」を実際には探していませんでした
Simon_Weaver

20

この質問はかなり古いですが、現在のバージョンの言語を活用する回答を残したいと思いました。残念ながら、静的クラスはまだTypeScriptには存在しませんが、クラスの外部からのインスタンス化を防ぐプライベートコンストラクターを使用して、わずかなオーバーヘッドのみで同様に動作するクラスを作成できます。

class MyStaticClass {
    public static readonly property: number = 42;
    public static myMethod(): void { /* ... */ }
    private constructor() { /* noop */ }
}

このスニペットを使用すると、C#の対応クラスと同様の「静的」クラスを使用できるようになりますが、内部からインスタンス化することは依然として可能です。幸い、プライベートコンストラクターでクラスを拡張することはできません。


9

これは1つの方法です。

class SomeClass {
    private static myStaticVariable = "whatever";
    private static __static_ctor = (() => { /* do static constructor stuff :) */ })();
}

__static_ctorこれはすぐに呼び出される関数式です。Typescriptは、生成されたクラスの最後にそれを呼び出すコードを出力します。

更新:静的メンバーによる参照が許可されなくなった静的コンストラクターのジェネリック型の場合、ここで追加の手順が必要になります。

class SomeClass<T> {
    static myStaticVariable = "whatever";
    private ___static_ctor = (() => { var someClass:SomeClass<T> ; /* do static constructor stuff :) */ })();
    private static __static_ctor = SomeClass.prototype.___static_ctor();
}

もちろん、いずれの場合も、次のよう、クラスの後にジェネリック型の静的コンストラクターを呼び出すだけです。

class SomeClass<T> {
    static myStaticVariable = "whatever";
    private __static_ctor = (() => { var example: SomeClass<T>; /* do static constructor stuff :) */ })();
}
SomeClass.prototype.__static_ctor();

上記で(明らかに)使用thisしないでください__static_ctor


この方法でも、クラスのコンストラクターが発行されます。
theycallmemorty

1
「この方法」はハックであり、期待どおりにコンパイラの通常の動作を変更しません。class SomeClass {}コンストラクタも生成します-新しい問題が導入されたかのようにコメントする価値はほとんどありません。;)参考までに:JSには実際の「コンストラクタ」はありません-オブジェクトまたはを介して呼び出されたときに「this」を持つ関数のみnewです。これは、「クラス」が何であっても存在します。
James Wilkins

6

今日(2018年7月31日)に同じ使用例を取得し、これが回避策であることがわかりました。それは私の研究に基づいており、私にとってはうまくいきました。 期待 -TypeScriptで次のことを達成するには:

var myStaticClass = {
    property: 10,
    method: function(){} 
}

これは私がしました:

//MyStaticMembers.ts
namespace MyStaticMembers {
        class MyStaticClass {
           static property: number = 10;
           static myMethod() {...}
        }
        export function Property(): number {
           return MyStaticClass.property;
        }
        export function Method(): void {
           return MyStaticClass.myMethod();
        }
     }

したがって、以下のように消費します。

//app.ts
/// <reference path="MyStaticMembers.ts" />
    console.log(MyStaticMembers.Property);
    MyStaticMembers.Method();

これでうまくいきました。誰か他のより良い提案がある場合は、私たち全員にそれを聞かせてください!!! ありがとう...


3

C#のような言語の静的クラスが存在するのは、データと関数をグループ化する他の最上位の構成要素がないためです。ただし、JavaScriptではそうなります。そのため、あなたがしたようにオブジェクトを宣言するだけの方がはるかに自然です。クラス構文をより厳密に模倣するには、次のようにメソッドを宣言できます。

const myStaticClass = {
    property: 10,

    method() {

    }
}

1
このアプローチはワークフローを混乱させませんか?一方ではクラスとインスタンスを使用し、その後突然通常の古いJSオブジェクトでデータの宣言を開始します...静的クラスを使用すると、読みやすさも向上します。これは、言語の内部動作だけではありません。
ココドコ2017

4
私のワークフローが邪魔になっているとは思いません。それどころか、モジュール内でクラスレスJavaScrpitオブジェクトまたは単純な関数と定数を使用することは非常に便利です。ただし、グローバルな状態をできるだけ避けようとするため、静的クラス変数のようなものはほとんど必要ありません。
ヨグ

1

見る http://www.basarat.com/2013/04/typescript-static-constructors-for.htmlをください

これは、静的コンストラクタを「偽造」する方法です。危険がないわけではありません。参照されているcodeplex項目を参照してください。

class Test {
    static foo = "orig";

    // Non void static function
    static stat() {
        console.log("Do any static construction here");
        foo = "static initialized";
        // Required to make function non void
        return null;
    }
    // Static variable assignment
    static statrun = Test.stat();
}

// Static construction will have been done:
console.log(Test.foo);

1

これを実現する1つの可能な方法は、クラスの静的インスタンスを別のクラス内に置くことです。例えば:

class SystemParams
{
  pageWidth:  number = 8270;
  pageHeight: number = 11690;  
}

class DocLevelParams
{
  totalPages: number = 0;
}

class Wrapper
{ 
  static System: SystemParams = new SystemParams();
  static DocLevel: DocLevelParams = new DocLevelParams();
}

次に、Wrapperを使用してパラメーターにアクセスできます。インスタンスを宣言する必要はありません。例えば:

Wrapper.System.pageWidth = 1234;
Wrapper.DocLevel.totalPages = 10;

したがって、JavaScript型オブジェクトの利点(元の質問で説明したとおり)が得られますが、TypeScript型付けを追加できるという利点があります。さらに、クラスのすべてのパラメーターの前に「静的」を追加する必要がなくなります。


1

ES6外部モジュールを使用すると、次のように実現できます。

// privately scoped array
let arr = [];

export let ArrayModule = {
    add: x => arr.push(x),
    print: () => console.log(arr),
}

これにより、TSLint [1] [2]によって悪い習慣と見なされている内部モジュールおよび名前空間の使用が防止され、プライベートおよびパブリックのスコープが許可され、不要なクラスオブジェクトの初期化が防止されます。


0

私は似たようなものを探していましたが、 Singleton Pattern

リファレンス:シングルトンパターン

BulkLoaderクラスでさまざまなタイプのファイルをロードするために作業しており、そのためにシングルトンパターンを使用したいと考えていました。このようにして、メインアプリケーションクラスからファイルをロードし、ロードしたファイルを他のクラスから簡単に取得できます。

以下は、TypeScriptとシングルトンパターンを使用してゲームのスコアマネージャーを作成する簡単な例です。

クラスSingletonClass {

private static _instance:SingletonClass = new SingletonClass();

private _score:number = 0;

constructor() {
    if(SingletonClass._instance){
        throw new Error("Error: Instantiation failed: Use SingletonDemo.getInstance() instead of new.");
    }
    SingletonClass._instance = this;
}

public static getInstance():SingletonClass
{
    return SingletonClass._instance;
}

public setScore(value:number):void
{
    this._score = value;
}

public getScore():number
{
    return this._score;
}

public addPoints(value:number):void
{
    this._score += value;
}

public removePoints(value:number):void
{
    this._score -= value;
}   }

次に、他のクラスのどこでも、次の方法でシングルトンにアクセスできます。

var scoreManager = SingletonClass.getInstance();
scoreManager.setScore(10); scoreManager.addPoints(1);
scoreManager.removePoints(2); console.log( scoreManager.getScore() );

0

キーワードnamespaceを使用して、変数、クラス、メソッドなどを整理することもできます。ドキュメントを参照

namespace Validation {
    export interface StringValidator {
        isAcceptable(s: string): boolean;
    }

    const lettersRegexp = /^[A-Za-z]+$/;
    const numberRegexp = /^[0-9]+$/;

    export class LettersOnlyValidator implements StringValidator {
        isAcceptable(s: string) {
            return lettersRegexp.test(s);
        }
    }

    export class ZipCodeValidator implements StringValidator {
        isAcceptable(s: string) {
            return s.length === 5 && numberRegexp.test(s);
        }
    }
}

参照してください上記のフロリアンのコメント:「これは推奨されません。またtslintあなたはモジュールや名前空間のためにもうそれを行うことはできません読むここpalantir.github.io/tslint/rules/no-namespace。。」
reggaeguitar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.