简体   繁体   English

TypeScript static 班

[英]TypeScript static classes

I wanted to move to TypeScript from traditional JS because I like the C#-like syntax.我想从传统的 JS 迁移到 TypeScript,因为我喜欢类似 C# 的语法。 My problem is that I can't find out how to declare static classes in TypeScript.我的问题是我找不到如何在 TypeScript 中声明 static 类。

In C#, I often use static classes to organize variables and methods, putting them together in a named class, without needing to instatiate an object. In vanilla JS, I used to do this with a simple JS object:在 C# 中,我经常使用 static 类来组织变量和方法,将它们放在一个命名为 class 中,而不需要实例化一个 object。在 vanilla JS 中,我曾经使用一个简单的 JS object 来做到这一点:

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

In TypeScript, I would rather go for my C-sharpy approach, but it seems that static classes don't exist in TS.在 TypeScript 中,我宁愿 go 用于我的 C-sharpy 方法,但似乎 static 类在 TS 中不存在。 What is the appropriate solution for this problem?这个问题的适当解决方案是什么?

Abstract classes have been a first-class citizen of TypeScript since TypeScript 1.6.自 TypeScript 1.6 以来,抽象类一直是 TypeScript 的一等公民。 You cannot instantiate an abstract class.您不能实例化抽象类。

Here is an example:下面是一个例子:

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

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

const okay = MyClass.doSomething();

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

TypeScript is not C#, so you shouldn't expect the same concepts of C# in TypeScript necessarily. TypeScript 不是 C#,因此您不必期望 TypeScript 中的 C# 概念一定相同。 The question is why do you want static classes?问题是你为什么想要静态类?

In C# a static class is simply a class that cannot be subclassed and must contain only static methods.在 C# 中,静态类只是一个不能被子类化并且只能包含静态方法的类。 C# does not allow one to define functions outside of classes. C# 不允许在类之外定义函数。 In TypeScript this is possible, however.然而,在 TypeScript 中这是可能的。

If you're looking for a way to put your functions/methods in a namespace (ie not global), you could consider using TypeScript's modules, eg如果您正在寻找一种将函数/方法放在命名空间(即非全局)中的方法,您可以考虑使用 TypeScript 的模块,例如

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

So that you can access Mf() externally, but not s, and you cannot extend the module.这样您就可以从外部访问 Mf(),但不能访问 s,并且您无法扩展模块。

See the TypeScript specification for more details.有关更多详细信息,请参阅 TypeScript 规范

Defining static properties and methods of a class is described in 8.2.1 of the Typescript Language Specification : 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); 
  } 
}

where Point.distance() is a static (or "class") method.其中Point.distance()是静态(或“类”)方法。

This question is quite dated yet I wanted to leave an answer that leverages the current version of the language.这个问题已经过时了,但我想留下一个利用该语言当前版本的答案。 Unfortunately static classes still don't exist in TypeScript however you can write a class that behaves similar with only a small overhead using a private constructor which prevents instantiation of classes from outside.不幸的是,TypeScript 中仍然不存在静态类,但是您可以使用私有构造函数编写一个行为相似的类,并且开销很小,从而防止从外部实例化类。

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

This snippet will allow you to use "static" classes similar to the C# counterpart with the only downside that it is still possible to instantiate them from inside.此代码段将允许您使用类似于 C# 对应物的“静态”类,唯一的缺点是仍然可以从内部实例化它们。 Fortunately though you cannot extend classes with private constructors.幸运的是,虽然您不能使用私有构造函数扩展类。

This is one way:这是一种方式:

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

__static_ctor here is an immediately invoked function expression. __static_ctor这里是一个立即调用的函数表达式。 Typescript will output code to call it at the end of the generated class. Typescript 将输出代码以在生成的类的末尾调用它。

Update: For generic types in static constructors, which are no longer allowed to be referenced by static members, you will need an extra step now:更新:对于不再允许静态成员引用的静态构造函数中的泛型类型,您现在需要一个额外的步骤:

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

In any case, of course, you could just call the generic type static constructor after the class, such as:在任何情况下,当然,您都可以在类之后调用泛型类型的静态构造函数,例如:

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

Just remember to NEVER use this in __static_ctor above (obviously).请记住永远不要在上面的__static_ctor使用this (显然)。

I got the same use case today(31/07/2018) and found this to be a workaround.我今天(31/07/2018)得到了相同的用例,并发现这是一种解决方法。 It is based on my research and it worked for me.它基于我的研究,对我有用。 Expectation - To achieve the following in TypeScript:期望- 在 TypeScript 中实现以下目标:

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

I did this:我这样做了:

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

Hence we shall consume it as below:因此,我们将使用它如下:

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

This worked for me.这对我有用。 If anyone has other better suggestions please let us all hear it !!!如果有人有其他更好的建议,请让我们都听到!!! Thanks...谢谢...

Static classes in languages like C# exist because there are no other top-level constructs to group data and functions.存在 C# 等语言中的静态类是因为没有其他顶级构造来对数据和函数进行分组。 In JavaScript, however, they do and so it is much more natural to just declare an object like you did.然而,在 JavaScript 中,它们确实如此,因此像您一样声明一个对象要自然得多。 To more closely mimick the class syntax, you can declare methods like so:为了更接近地模仿类语法,您可以像这样声明方法:

const myStaticClass = {
    property: 10,

    method() {

    }
}

With ES6 external modules this can be achieved like so:使用 ES6 外部模块,可以这样实现:

// privately scoped array
let arr = [];

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

This prevents the use of internal modules and namespaces which is considered bad practice by TSLint [1] [2] , allows private and public scoping and prevents the initialisation of unwanted class objects.这可以防止使用被 TSLint [1] [2]认为是不好的做法的内部模块和命名空间,允许私有和公共范围并防止初始化不需要的类对象。

See http://www.basarat.com/2013/04/typescript-static-constructors-for.htmlhttp://www.basarat.com/2013/04/typescript-static-constructors-for.html

This is a way to 'fake' a static constructor.这是一种“伪造”静态构造函数的方法。 It's not without its dangers - see the referenced codeplex item .它并非没有危险 - 请参阅引用的 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);

One possible way to achieve this is to have static instances of a class within another class.实现这一点的一种可能方法是在另一个类中拥有一个类的静态实例。 For example:例如:

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

Then parameters can be accessed using Wrapper, without having to declare an instance of it.然后可以使用 Wrapper 访问参数,而无需声明它的实例。 For example:例如:

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

So you get the benefits of the JavaScript type object (as described in the original question) but with the benefits of being able to add the TypeScript typing.因此,您可以获得 JavaScript 类型对象的好处(如原始问题中所述),但可以添加 TypeScript 类型的好处。 Additionally, it avoids having to add 'static' in front of all the parameters in the class.此外,它避免了必须在类中的所有参数前添加“静态”。

My preferred method is to just use a const object (mainly instead of enums):我的首选方法是只使用 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');

Check this TS playground .检查这个 TS 游乐场

I was searching for something similar and came accross something called the Singleton Pattern .我正在寻找类似的东西,并遇到了一种叫做Singleton Pattern东西。

Reference: Singleton Pattern参考: 单例模式

I am working on a BulkLoader class to load different types of files and wanted to use the Singleton pattern for it.我正在使用 BulkLoader 类来加载不同类型的文件,并希望对其使用单例模式。 This way I can load files from my main application class and retrieve the loaded files easily from other classes.这样我就可以从我的主应用程序类加载文件并从其他类轻松检索加载的文件。

Below is a simple example how you can make a score manager for a game with TypeScript and the Singleton pattern.下面是一个简单的示例,您可以使用 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; } }

Then anywhere in your other classes you would get access to the Singleton by:然后在您的其他类中的任何地方,您都可以通过以下方式访问 Singleton:

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

You can also use keyword namespace to organize your variables, classes, methods and so on.您还可以使用关键字namespace来组织您的变量、类、方法等。 See doc文档

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

You can create a class in Typescript as follows:您可以在 Typescript 中创建一个类,如下所示:

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

and reference it's properties and methods "without" instantiation so:并在“没有”实例化的情况下引用它的属性和方法,因此:

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

Fyi using backticks `` in conjunction with interpolation syntax ${} allows ease in mixing code with text :-)仅供参考,使用反引号 `` 结合插值语法 ${} 可以轻松地将代码与文本混合:-)

You can use abstract classes with public static readonly members to achieve something very similar to what you're looking for.您可以使用带有public static readonly 成员的抽象类来实现与您正在寻找的非常相似的东西。 I believe you're looking for something like a struct from C# or C/C++ to organise small pieces of data together.我相信您正在寻找类似 C# 或 C/C++ struct东西来将小块数据组织在一起。

The cool thing about abstract classes is that抽象类很酷的一点是

  • they cannot be instantiated,它们不能被实例化,
  • they can only be derived from and它们只能来自和
  • they can provide base implementations for some or all of the methods defined in them.它们可以为其中定义的部分或全部方法提供基本实现。

You can even use this technique to somewhat mimic an enum (you can't switch on them for example) but have properties that can be more than just strings or numbers.您甚至可以使用此技术在某种程度上模拟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