TypeScript статические классы
Я хотел перейти к TypeScript из традиционного JS, потому что мне нравится синтаксис, похожий на С#.
Моя проблема в том, что я не могу узнать, как объявлять статические классы в TypeScript.
В С# я часто использую статические классы для организации переменных и методов, объединяя их в именованный класс без необходимости создания объекта.
В vanilla JS я использовал это с помощью простого объекта JS:
var myStaticClass = {
property: 10,
method: function(){}
}
В TypeScript, я бы предпочел использовать мой подход C-sharpy, но кажется, что статические классы не существуют в TS.
Какое подходящее решение для этой проблемы?
Ответы
Ответ 1
TypeScript не является С#, поэтому вам не следует ожидать, что те же концепции С# в TypeScript обязательно. Вопрос в том, зачем вам статические классы?
В С# статический класс - это просто класс, который не может быть подклассифицирован и должен содержать только статические методы. С# не позволяет определять функции вне классов. Однако в TypeScript это возможно.
Если вы ищете способ разместить свои функции/методы в пространстве имен (т.е. не глобальном), вы можете рассмотреть возможность использования модулей TypeScript, например.
module M {
var s = "hello";
export function f() {
return s;
}
}
Чтобы вы могли получить доступ к M.f() извне, но не s, и вы не можете расширять модуль.
Подробнее см. TypeScript specification.
Ответ 2
Определение статических свойств и методов класса описано в 8.2.1 Typescript Спецификация языка:
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()
- статический (или "классный" ) метод.
Ответ 3
Чтобы сделать класс static-like в TypeScript, вы можете пометить все свойства и методы как статические, о чем упомянули некоторые люди, - но помимо этого вы также можете обеспечить, чтобы новые экземпляры класса генерировали исключение для предотвращения экземпляров создается. Это существенно заставляет класс использоваться только статическим образом, хотя ошибка - это время выполнения, а не время компиляции.
export abstract class MyClass {
public static myProp = "Hello";
public static doSomething(): string {
return "World";
}
}
const x = MyClass.doSomething();
//const example = new MyClass(); // Error
Ответ 4
Это один из способов:
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.___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
выше (очевидно).
Ответ 5
См. 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);
Ответ 6
Я искал что-то похожее и получил нечто вроде Singleton Pattern
.
Ссылка: Шаблон Singleton
Я работаю над классом BulkLoader для загрузки различных типов файлов и хотел использовать шаблон Singleton для него. Таким образом, я могу загружать файлы из моего основного класса приложения и легко загружать загруженные файлы из других классов.
Ниже приведен простой пример того, как вы можете создать менеджера очков для игры с 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;
} }
Тогда в любом месте других классов вы получите доступ к Singleton by:
var scoreManager = SingletonClass.getInstance();
scoreManager.setScore(10); scoreManager.addPoints(1);
scoreManager.removePoints(2); console.log( scoreManager.getScore() );
Ответ 7
Статические классы в таких языках, как С#, существуют, потому что нет других конструкций верхнего уровня для группировки данных и функций. В JavaScript, однако, они делают, и поэтому гораздо более естественно просто объявить объект, как вы. Чтобы более точно сопоставить синтаксис класса, вы можете объявить такие методы:
const myStaticClass = {
property: 10,
method() {
}
}
Ответ 8
Одним из возможных способов достижения этого является наличие статических экземпляров класса в другом классе. Например:
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 ввода. Кроме того, он избегает добавления "статического" перед всеми параметрами в классе.
Ответ 9
Вы также можете использовать ключевое слово namespace
для упорядочивания переменных, классов, методов и т.д. См. 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);
}
}
}