Pendant ce temps, cela peut être résolu par un décorateur en combinaison avec Object.freezeou Object.defineProperty, j'utilise ceci, c'est un peu plus joli que d'utiliser des tonnes de getters. Vous pouvez copier / coller directement ce TS Playground pour le voir en action. - Il y a deux options
Rendre les champs individuels "définitifs"
Le décorateur suivant convertit les champs statiques annotés et non statiques en "propriétés de lecture uniquement".
Remarque : Si une variable d'instance sans valeur initiale est annotée @final, la première valeur attribuée (peu importe quand) sera la dernière.
// 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.
Le décorateur: assurez-vous de l'inclure dans votre code!
/**
* 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
});
}
}
Comme alternative au décorateur ci-dessus, il y aurait également une version stricte de celui-ci, qui lèverait même une erreur lorsque quelqu'un essaierait d'attribuer une valeur au champ en "use strict";cours de définition. (Ce n'est cependant que la partie statique)
/**
* 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
});
}
Rendre chaque champ statique "définitif"
Inconvénient possible: cela ne fonctionnera que pour TOUTES les statiques de cette classe ou pour aucune, mais ne peut pas être appliqué à des statiques spécifiques.
/**
* 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."