public static const v TypeScripte


Existuje niečo také ako verejné statické konštanty v TypeScripte? Mám triedu, ktorá vyzerá takto:

export class Library {
  public static BOOK_SHELF_NONE: string = "None";
  public static BOOK_SHELF_FULL: string = "Full";
}

V tejto triede môžem použiť Library.BOOK_SHELF_NONE a tsc na to nenadáva. Ale ak sa pokúsim použiť triedu Library inde a urobiť to isté, nerozpozná to.

Odpoveď č. 1

Ak by ste chceli niečo, čo sa správa viac ako statická konštantná hodnota v moderných prehliadačoch (t. j. nemôže byť zmenené iným kódom), môžete pridať prístupovú metódu get iba pre triedu Library (toto bude fungovať iba pre prehliadače ES5+ a NodeJS):

export class Library {
    public static get BOOK_SHELF_NONE():string { return "None"; }
    public static get BOOK_SHELF_FULL():string { return "Full"; }   
}

var x = Library.BOOK_SHELF_NONE;
console.log(x);
Library.BOOK_SHELF_NONE = "Not Full";
x = Library.BOOK_SHELF_NONE;
console.log(x);

Ak ho spustíte, uvidíte, ako sa pokus nastaviť vlastnosť BOOK_SHELF_NONE na novú hodnotu nepodarí.

2.0

V TypeScripte 2.0 môžete použiť readonly na dosiahnutie veľmi podobných výsledkov:

export class Library {
    public static readonly BOOK_SHELF_NONE = "None";
    public static readonly BOOK_SHELF_FULL = "Full";
}

Syntax je o niečo jednoduchšia a zrejmejšia. Kompilátor však zabraňuje zmenám skôr než čas vykonávania (na rozdiel od prvého príkladu, kde by zmena nebola vôbec povolená, ako bolo demonštrované).

Odpoveď č. 2

Môžete to urobiť pomocou menných priestorov, takto:

export namespace Library {
    export const BOOK_SHELF_NONE: string = 'NONE';
}

Potom ho môžete importovať odkiaľkoľvek inde:

import {Library} from './Library';
console.log(Library.BOOK_SHELF_NONE);

Ak potrebujete triedu aj tam, zahrňte ju do namespace: export class Book {...}

Odpoveď č. 3

Tu je, do čoho je tento TS útržok skompilovaný (cez TS Playground):

define(["require", "exports"], function(require, exports) {
    var Library = (function () {
        function Library() {
        }
        Library.BOOK_SHELF_NONE = "None";
        Library.BOOK_SHELF_FULL = "Full";
        return Library;
    })();
    exports.Library = Library;
});

Ako vidíte, obe vlastnosti definované ako public static sú jednoducho pripojené k exportovanej funkcii (ako jej vlastnosti); preto by mali byť prístupné, pokiaľ správne pristupujete k samotnej funkcii.

Odpoveď č. 4

Medzitým sa to dá vyriešiť cez dekorátor v kombinácii s Object.freeze alebo Object.defineProperty, používam to, je to o niečo krajšie ako používanie množstva getterov. Môžete to skopírovať/prilepiť priamo do TS Playground, aby ste to videli v akcii. - Sú dve možnosti

Urobte jednotlivé polia „finálne“

Nasledujúci dekorátor prevádza anotované statické aj nestatické polia na „vlastnosti iba s getterom“.

Poznámka: Ak je inštančná premenná bez počiatočnej hodnoty označená @final, potom prvá priradená hodnota (bez ohľadu na to, kedy) bude konečná.

// example
class MyClass {
    @final
    public finalProp: string = "You shall not change me!";

    @final
    public static FINAL_FIELD: number = 75;

    public static NON_FINAL: string = "I am not final."
}

var myInstance: MyClass = new MyClass();
myInstance.finalProp = "Was I changed?";
MyClass.FINAL_FIELD = 123;
MyClass.NON_FINAL = "I was changed.";

console.log(myInstance.finalProp);  // => You shall not change me!
console.log(MyClass.FINAL_FIELD);   // => 75
console.log(MyClass.NON_FINAL);     // => I was changed.

Decorator: Uistite sa, že to zahrniete do svojho kódu!

/**
* Turns static and non-static fields into getter-only, and therefor renders them "final".
* To use simply annotate the static or non-static field with: @final
*/
function final(target: any, propertyKey: string) {
    const value: any = target[propertyKey];
    // if it currently has no value, then wait for the first setter-call
    // usually the case with non-static fields
    if (!value) {
        Object.defineProperty(target, propertyKey, {
            set: function (value: any) {
                Object.defineProperty(this, propertyKey, {
                    get: function () {
                        return value;
                    },
                    enumerable: true,
                    configurable: false
                });
            },
            enumerable: true,
            configurable: true
        });
    } else { // else, set it immediatly
        Object.defineProperty(target, propertyKey, {
            get: function () {
                return value;
            },
            enumerable: true
        });
    }
}

Ako alternatíva k vyššie uvedenému dekorátoru by existovala aj prísna verzia tohto, ktorá by dokonca vyhodila Chybu, keď by sa niekto pokúsil priradiť nejakú hodnotu do poľa s nastaveným "use strict";. (Toto je však iba statická časť)

/**
 * Turns static fields into getter-only, and therefor renders them "final".
 * Also throws an error in strict mode if the value is tried to be touched.
 * To use simply annotate the static field with: @strictFinal
 */
function strictFinal(target: any, propertyKey: string) {
    Object.defineProperty(target, propertyKey, {
        value: target[propertyKey],
        writable: false,
        enumerable: true
    });
}

Urobte každé statické pole „final“

Možná nevýhoda: Toto bude fungovať iba pre VŠETKY statické členy tejto triedy alebo pre žiadne, ale nemožno to aplikovať na konkrétne statické členy.

/**
* Freezes the annotated class, making every static 'final'.
* Usage:
* @StaticsFinal
* class MyClass {
*      public static SOME_STATIC: string = "SOME_STATIC";
*      //...
* }
*/
function StaticsFinal(target: any) {
    Object.freeze(target);
}
// Usage here
@StaticsFinal
class FreezeMe {
    public static FROZEN_STATIC: string = "I am frozen";
}

class EditMyStuff {
    public static NON_FROZEN_STATIC: string = "I am frozen";
}

// Test here
FreezeMe.FROZEN_STATIC = "I am not frozen.";
EditMyStuff.NON_FROZEN_STATIC = "I am not frozen.";

console.log(FreezeMe.FROZEN_STATIC); // => "I am frozen."
console.log(EditMyStuff.NON_FROZEN_STATIC); // => "I am not frozen."

Súvisiace články