簡體   English   中英

TypeScript static 班

[英]TypeScript static classes

我想從傳統的 JS 遷移到 TypeScript,因為我喜歡類似 C# 的語法。 我的問題是我找不到如何在 TypeScript 中聲明 static 類。

在 C# 中,我經常使用 static 類來組織變量和方法,將它們放在一個命名為 class 中,而不需要實例化一個 object。在 vanilla JS 中,我曾經使用一個簡單的 JS object 來做到這一點:

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

在 TypeScript 中,我寧願 go 用於我的 C-sharpy 方法,但似乎 static 類在 TS 中不存在。 這個問題的適當解決方案是什么?

自 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

TypeScript 不是 C#,因此您不必期望 TypeScript 中的 C# 概念一定相同。 問題是你為什么想要靜態類?

在 C# 中,靜態類只是一個不能被子類化並且只能包含靜態方法的類。 C# 不允許在類之外定義函數。 然而,在 TypeScript 中這是可能的。

如果您正在尋找一種將函數/方法放在命名空間(即非全局)中的方法,您可以考慮使用 TypeScript 的模塊,例如

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

這樣您就可以從外部訪問 Mf(),但不能訪問 s,並且您無法擴展模塊。

有關更多詳細信息,請參閱 TypeScript 規范

Typescript Language Specification 的8.2.1 描述了定義類的靜態屬性和方法:

class Point { 
  constructor(public x: number, public y: number) { 
    throw new Error('cannot instantiate using a static class');
  } 
  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()是靜態(或“類”)方法。

這個問題已經過時了,但我想留下一個利用該語言當前版本的答案。 不幸的是,TypeScript 中仍然不存在靜態類,但是您可以使用私有構造函數編寫一個行為相似的類,並且開銷很小,從而防止從外部實例化類。

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

此代碼段將允許您使用類似於 C# 對應物的“靜態”類,唯一的缺點是仍然可以從內部實例化它們。 幸運的是,雖然您不能使用私有構造函數擴展類。

這是一種方式:

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

請記住永遠不要在上面的__static_ctor使用this (顯然)。

我今天(31/07/2018)得到了相同的用例,並發現這是一種解決方法。 它基於我的研究,對我有用。 期望- 在 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();

這對我有用。 如果有人有其他更好的建議,請讓我們都聽到!!! 謝謝...

存在 C# 等語言中的靜態類是因為沒有其他頂級構造來對數據和函數進行分組。 然而,在 JavaScript 中,它們確實如此,因此像您一樣聲明一個對象要自然得多。 為了更接近地模仿類語法,您可以像這樣聲明方法:

const myStaticClass = {
    property: 10,

    method() {

    }
}

使用 ES6 外部模塊,可以這樣實現:

// privately scoped array
let arr = [];

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

這可以防止使用被 TSLint [1] [2]認為是不好的做法的內部模塊和命名空間,允許私有和公共范圍並防止初始化不需要的類對象。

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

實現這一點的一種可能方法是在另一個類中擁有一個類的靜態實例。 例如:

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 類型的好處。 此外,它避免了必須在類中的所有參數前添加“靜態”。

我的首選方法是只使用 const object(主要代替枚舉):

const RequestTypes2 = {
    All: 'All types',
    Partners: 'Partners',
    Articles: 'Articles',
} as const; // need the "const" to force the property types to be string literal types (hover RequestTypes2 to see!)

// now you can do this (hover AllowedRequestTypes to see the inferred type)
type AllowedRequestTypes = typeof RequestTypes2[keyof typeof RequestTypes2];

function doRequest(requestType: AllowedRequestTypes) {

}

// these should work 
doRequest('Partners');
doRequest(RequestTypes2.All);
doRequest(RequestTypes.Articles);   // the property's type is "Articles" (string literal type)

// this fails
doRequest('Incorrect');

檢查這個 TS 游樂場

我正在尋找類似的東西,並遇到了一種叫做Singleton Pattern東西。

參考: 單例模式

我正在使用 BulkLoader 類來加載不同類型的文件,並希望對其使用單例模式。 這樣我就可以從我的主應用程序類加載文件並從其他類輕松檢索加載的文件。

下面是一個簡單的示例,您可以使用 TypeScript 和 Singleton 模式為游戲制作分數管理器。

類單例類{

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

然后在您的其他類中的任何地方,您都可以通過以下方式訪問 Singleton:

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

您還可以使用關鍵字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);
        }
    }
}

您可以在 Typescript 中創建一個類,如下所示:

export class Coordinate {
        static x: number;
        static y: number;
        static gradient() {
            return y/x;
        }
    }

並在“沒有”實例化的情況下引用它的屬性和方法,因此:

Coordinate.x = 10;
Coordinate.y = 10;
console.log(`x of ${Coordinate.x} and y of ${Coordinate.y} has gradient of ${Coordinate.gradient()}`);

僅供參考,使用反引號 `` 結合插值語法 ${} 可以輕松地將代碼與文本混合:-)

您可以使用帶有public static readonly 成員的抽象類來實現與您正在尋找的非常相似的東西。 我相信您正在尋找類似 C# 或 C/C++ struct東西來將小塊數據組織在一起。

抽象類很酷的一點是

  • 它們不能被實例化,
  • 它們只能來自和
  • 它們可以為其中定義的部分或全部方法提供基本實現。

您甚至可以使用此技術在某種程度上模擬enum (例如,您無法打開它們)但具有的屬性可能不僅僅是字符串或數字。

// you can omit the public keyword because it's the default in TS, I left it here for clarity

export abstract class RequestTypes {
  public static readonly All = 'All types';
  public static readonly Partners = 'Partners';
  public static readonly Articles = 'Articles';
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM