TypeScript 静态类

我想从传统的 JS 转向 TypeScript,因为我喜欢类似 C# 风格的语法。 我的问题是我不知道如何在 TypeScript 中声明静态类 在c#中,我经常使用静态类来组织变量和方法,将它们放在一个命名类中,而不需要实例化一个对象。 在香草JS中,我习惯用一个简单的JS对象来做到这一点:

var myStaticClass = {
property: 10,
method: function(){}
}
在TypeScript中,我宁愿使用我的C-sharpy方法,但TS中似乎不存在静态类。

248165 次浏览

TypeScript不是c#,所以你不应该期望在TypeScript中使用相同的c#概念。问题是为什么需要静态类?

在c#中,静态类只是不能子类化的类,必须只包含静态方法。c#不允许在类之外定义函数。然而,在TypeScript中,这是可能的。

如果你正在寻找一种方法将你的函数/方法放在一个命名空间中(即不是全局的),你可以考虑使用TypeScript的模块,例如:

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

这样您可以从外部访问M.f(),但不能访问s,并且您不能扩展模块。

更多细节请参见TypeScript 规范

定义类的静态属性和方法在语言说明的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()是一个静态(或“类”)方法。

< p >更新: 上面的链接已经更新到Typescript规范的最新可用版本,但请注意,根据https://github.com/Microsoft/TypeScript/issues/15711,目前没有Typescript的权威规范,预计也不会有

自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

这是一种方法:

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(显然)。

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

我正在搜索类似的东西,遇到了一个叫做Singleton Pattern的东西。

参考:单例模式

我在一个BulkLoader类加载不同类型的文件和 我想使用单例模式。这样我就可以加载文件了 从我的主应用程序类和检索加载的文件很容易

下面是一个简单的例子,如何为游戏创建一个分数管理器

.使用TypeScript和Singleton模式

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

那么在你的其他类的任何地方你都可以访问 单例模式:< / p >

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

在c#等语言中存在静态类是因为没有其他顶级结构来对数据和函数进行分组。然而,在JavaScript中,它们是这样做的,所以像你这样声明一个对象要自然得多。为了更接近地模仿类语法,你可以这样声明方法:

const myStaticClass = {
property: 10,


method() {


}
}

实现这一点的一种可能方法是在另一个类中拥有一个类的静态实例。例如:

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类型。此外,它避免了在类的所有参数前添加“static”。

你也可以使用关键字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中,但是你可以编写一个行为类似的类,只需要使用一个私有构造函数来防止从外部实例化类,开销很小。

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

这个代码片段将允许您使用类似于c#的“静态”类,唯一的缺点是仍然可以从内部实例化它们。幸运的是,你不能用私有构造函数扩展类。

我今天(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();
这对我很管用。如果任何人有其他更好的建议,请让我们都听到!! 谢谢…< / p >

使用ES6外部模块,这可以像这样实现:

// privately scoped array
let arr = [];


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

这可以防止使用内部模块和命名空间,这在TSLint [1] [2]中被认为是不好的做法,允许私有和公共作用域,并防止初始化不需要的类对象。

你可以像下面这样在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()}`);

供参考,使用反撇号' '结合插值语法${}可以轻松地将代码与文本混合:-)

你可以使用抽象类公共静态只读成员来实现与你正在寻找的东西非常相似的东西。我相信你正在寻找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';
}

我的首选方法是只使用const对象(主要而不是枚举):

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游乐场