Clase statice TypeScript (Programare, Javascript, Clasa, Static, Typescript)

Rayjax a intrebat.
a intrebat.

Am vrut să trec la TypeScript de la JS tradițional pentru că îmi place sintaxa asemănătoare cu cea din C#.Problema mea este că nu pot afla cum să declar clasele statice în TypeScript.

În C#, folosesc deseori clasele statice pentru a organiza variabilele și metodele, punându-le împreună într-o clasă cu nume, fără a fi nevoie să instiți un obiect. în vanilla JS, obișnuiam să fac acest lucru cu un simplu obiect JS:

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

În TypeScript, aș prefera să merg mai degrabă pe abordarea mea C-sharpy, dar se pare că clasele statice nu există în TS. Care este soluția potrivită pentru această problemă ?

13 răspunsuri
Marcus

TypeScript nu este C#, deci nu ar trebui să vă așteptați neapărat la aceleași concepte din C# în TypeScript. Întrebarea este de ce doriți clase statice?

În C#, o clasă statică este pur și simplu o clasă care nu poate fi subclasată și trebuie să conțină doar metode statice. C# nu permite definirea de funcții în afara claselor. În TypeScript acest lucru este posibil, totuși.

Dacă sunteți în căutarea unei modalități de a vă plasa funcțiile/metodele într-un spațiu de nume (adică nu global), ați putea lua în considerare utilizarea modulelor TypeScript, de ex.

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

astfel încât să puteți accesa M.f() din exterior, dar nu și s, și nu puteți extinde modulul.

Consultați pagina de internet TypeScript pentru mai multe detalii.

Comentarii

  • astfel încât un modul să poată avea o metodă statică, dar o clasă nu? dar modulele nu pot avea date statice. Nu este la fel de convenabil ca JS pentru a înfășura date și cod fără a fi nevoie să instanțiezi nimic. –  > Por dcsan.
  • Ar putea fi util să includeți faptul că va trebui să includeți .js în html. Deci, pentru Angular 2 probabil că veți folosi System… așa că ar trebui să faceți System.import("Folder/M"); (sau oricare ar fi calea de acces la fișierul compilat). .js ) înainte de bootstrap import –  > Por Serj Sagan.
  • 15

  • Acest lucru este depreciat. De asemenea, tslint nu vă va mai permite să faceți acest lucru pentru module și spații de nume. Citiți aici: palantir.github.io/tslint/rules/no-namespace –  > Por Florian Leitgeb.
  • Am un caz de utilizare pentru a avea clase statice. În acest moment, am o clasă care conține doar metode statice. În proiect trebuie să furnizăm un fel de configurare pentru fiecare clasă care poate fi instanțiată. Declararea unei astfel de clase ca fiind statică nu numai că m-ar ajuta să observ că nu va fi instanțiată, dar ar evita și ca alți dezvoltatori să îi adauge membri de instanță. –  > Por mdarefull.
  • @florian leitgeb care este calea preferată atunci, o clasă cu doar metode statice și/sau cuvânt cheie abstract? Asta pare o porcărie în comparație cu modulul care acum pare a fi depreciat – -.  > Por wired00.
Fenton

Clasele abstracte au fost un cetățean de primă clasă al TypeScript încă de la TypeScript 1.6. Nu puteți instanția o clasă abstractă.

Iată un exemplu:

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

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

const okay = MyClass.doSomething();

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

Comentarii

  • Când aveți de-a face cu clase statice, acesta este cel mai bun răspuns și îl votez. Singleton este pentru modelul de memorie partajată a aceleiași instanțe de clasă. De asemenea, o clasă statică nu are o instanță prin definiție, deci trebuie să aruncați o excepție dacă clientul încearcă să o inițializeze. –  > Por loretoparisi.
  • Putem face o clasă abstractă? –  > Por KimchiMan.
  • @KimchiMan – da, se poate crea o clasă abstract este acceptat în TypeScript. –  > Por Fenton.
  • Actualizat pentru a utiliza abstract! @KimchiMan – o idee grozavă! –  > Por mattyb.
  • Este aceasta o abordare mai bună decât marcarea constructorului ca fiind privat? –  > Por Joro Tenev.
Rob Raisch

Definirea proprietăților și metodelor statice ale unei clase este descrisă în 8.2.1 din Specificația limbajului Typescript:

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

unde Point.distance() este o metodă statică (sau „de clasă”).

Comentarii

    19

  • Acest lucru arată cum se creează o metodă statică staticădar nu răspunde la întrebarea care se referă la metode statice. clasele statice (cu excepția cazului în care întrebarea reală se referă de fapt la metodele statice). –  > Por Marcus.
  • 21

  • Mulțumesc pentru comentariu. Descrie modul de creare a proprietăților și metodelor statice, care, luate împreună, permit crearea unei clase cu date și funcționalitate fără a fi nevoie de instanțiere. Deși nu este în mod specific o „clasă statică”, îndeplinește cerința descrisă de exemplul JavaScript al OP. –  > Por Rob Raisch.
  • c# nu a avut clase statice până la versiunea 2. ele există în c# doar pentru a te împiedica să le instanțiezi. nu poți face asta cu javascript, așa că nu prea are sens –  > Por Simon_Weaver.
  • @Simon_Weaver Nu poți face ce în javascript? Să împiedici clasele să fie instanțiate? Typescript nu-i pasă prea mult de timpul de execuție oricum, atâta timp cât primești o eroare de compilare atunci când încerci să faci lucruri pe care nu ai voie să le faci, asta e tot ce avem nevoie. –  > Por Alex.
  • Cred că ceea ce am vrut să spun a fost „nu am avut cuvântul cheie static la nivel de clasă (ceea ce înseamnă că nu poți crea o instanță a unei clase)” până la versiunea 2. Dar, citind din nou, cred că comentariul meu a cam ratat ideea, oricum. OP nu căuta cu adevărat un „cuvânt cheie static” pentru întreaga clasă…  > Por Simon_Weaver.
Christian Ivicevic

Această întrebare este destul de veche, dar am vrut să las un răspuns care să valorifice versiunea actuală a limbajului. Din păcate, clasele statice încă nu există în TypeScript, însă puteți scrie o clasă care se comportă similar cu un mic cost suplimentar, folosind un constructor privat care împiedică instanțierea claselor din exterior.

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

Acest fragment vă va permite să folosiți clase „statice” similare cu omologul C#, cu singurul dezavantaj că este încă posibilă instanțierea lor din interior. Din fericire însă, nu puteți extinde clasele cu constructori privați.

James Wilkins

Aceasta este o modalitate:

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

__static_ctor aici este o expresie de funcție imediat invocată. Typescript va scoate codul pentru a o apela la sfârșitul clasei generate.

Actualizare: Pentru tipurile generice din constructorii statici, care nu mai au voie să fie referite de membrii statici, veți avea nevoie de un pas suplimentar acum:

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

În orice caz, bineînțeles, ați putea să apelați pur și simplu constructorul static al tipului generic după clasa, cum ar fi:

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

Nu uitați să nu folosiți NICIODATĂ this în __static_ctor de mai sus (evident).

Comentarii

  • În acest fel, se emite în continuare un constructor pentru clasă. –  > Por theycallmemorty.
  • „This way” este un hack, și nu schimbă funcționarea normală a compilatorului, așa cum era de așteptat. Chiar și class SomeClass {} generează un constructor – nu prea merită comentat ca și cum ar fi introdusă o nouă problemă. 😉 FYI: Nu există „constructori” reali în JS – doar funcții care au un „this” atunci când sunt apelate pe obiecte, sau prin intermediul new. Acest lucru există indiferent pentru orice „clasă”. –  > Por James Wilkins.
KoRa

Am avut același caz de utilizare astăzi(31/07/2018) și am descoperit că aceasta este o soluție de rezolvare. Se bazează pe cercetările mele și a funcționat pentru mine.Așteptare – Pentru a realiza următoarele în TypeScript:

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

Am făcut acest lucru:

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

Prin urmare, îl vom consuma ca mai jos:

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

Acest lucru a funcționat pentru mine. Dacă cineva are alte sugestii mai bune, vă rugăm să ne anunțați pe toți!!!Mulțumesc…

Yogu

Clasele statice în limbaje precum C# există pentru că nu există alte construcții de nivel superior pentru a grupa date și funcții. În JavaScript, însă, există și, prin urmare, este mult mai natural să declari un obiect așa cum ai făcut tu. Pentru a imita mai îndeaproape sintaxa claselor, puteți declara metode astfel:

const myStaticClass = {
    property: 10,

    method() {

    }
}

Comentarii

  • Această abordare nu vă încurcă fluxul de lucru? Pe de o parte, folosiți clase și instanțe, iar apoi, brusc, începeți din nou să declarați date în obiecte JS obișnuite… Utilizarea claselor statice ajută, de asemenea, la lizibilitate, nu este vorba doar de funcționarea internă a limbajului. –  > Por Kokodoko.
  • Nu mi se pare că îmi încurcă fluxul de lucru; dimpotrivă, mi se pare foarte convenabil să folosesc obiecte JavaScrpit fără clase sau doar funcții și constante simple într-un modul. Cu toate acestea, încerc, de asemenea, să evit cât mai mult posibil să am o stare globală, așa că rareori am nevoie de ceva de genul variabilelor de clasă statice. –  > Por Yogu.
wizzfizz94

Cu modulele externe ES6, acest lucru poate fi realizat astfel:

// privately scoped array
let arr = [];

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

Acest lucru previne utilizarea modulelor interne și a spațiilor de nume, ceea ce este considerat o practică proastă de către TSLint [1] [2], permite o încadrare privată și publică și previne inițializarea obiectelor de clasă nedorite.

Simon_Weaver

A se vedea http://www.basarat.com/2013/04/typescript-static-constructors-for.html

Aceasta este o modalitate de a „falsifica” un constructor static. Nu este lipsit de pericole – a se vedea elementul codeplex la care se face referire.

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

Steve Roberts

O modalitate posibilă de a realiza acest lucru este de a avea instanțe statice ale unei clase în cadrul altei clase. De exemplu:

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

Apoi, parametrii pot fi accesați folosind Wrapper, fără a fi nevoie să se declare o instanță a acesteia. De exemplu:

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

Astfel, obțineți avantajele obiectului de tip JavaScript (așa cum este descris în întrebarea inițială), dar cu avantajele de a putea adăuga tipizarea TypeScript. În plus, se evită necesitatea de a adăuga „static” în fața tuturor parametrilor din clasă.

stoXe

Am căutat ceva similar și am dat peste ceva numit Singleton Pattern.

Referință: Modelul Singleton

Lucrez la o clasă BulkLoader pentru a încărca diferite tipuri de fișiere și am vrut să folosesc modelul Singleton pentru aceasta. În acest fel, pot încărca fișiere din clasa principală a aplicației mele și pot prelua cu ușurință fișierele încărcate din alte clase.

Mai jos este un exemplu simplu despre cum se poate realiza un manager de scoruri pentru un joc cu TypeScript și modelul Singleton.

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

Apoi, oriunde în celelalte clase ale dvs. veți avea acces la Singleton prin:

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

jaguar7021

De asemenea, puteți utiliza cuvântul cheie namespace pentru a vă organiza variabilele, clasele, metodele și așa mai departe. A se vedea 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);
        }
    }
}

Comentarii

  • Consultați comentariul lui Florian de mai sus „Acest lucru este depreciat. De asemenea, tslint nu vă va mai permite să faceți acest lucru pentru module și spații de nume. Citiți aici: palantir.github.io/tslint/rules/no-namespace” –  > Por reggaeguitar.
Kieran Ryan

Puteți crea o clasă în Typescript după cum urmează:

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

și să faceți referire la proprietățile și metodele sale „fără” instanțiere, astfel: – Faceți o clasă:

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

Fyi utilizarea backticks „ împreună cu sintaxa de interpolare ${} permite ușurința în amestecarea codului cu textul 🙂