Je suis seul avec le calendrier de l'avent TypeScript, je vais donc vous présenter ce que j'ai écrit plus tôt.
Enum existe également dans Typescript, mais je ne suis pas doué pour définir des fonctions ou gérer plusieurs valeurs ensemble. (Vous ne pouvez rien faire avec namespace
](https://qiita.com/ConquestArrow/items/5d885128f896844698dd#%E9%96%A2%E6%95%B0%E3%82%84enum%E3 % 82% 92% E6% 8B% A1% E5% BC% B5))
J'utilise généralement Java, donc quand je travaillais avec Typescript, je voulais quelque chose comme Enum de Java.
Donc, j'ai essayé d'exprimer quelque chose comme Enum de Java dans une classe avec Typescript. (Quelque chose comme ca)
Je suis sûr qu'il y a des gens qui le font pour acquis même si on ne le leur dit pas, mais je vais le laisser à la place de mes propres notes.
Tout d'abord, listons ce que vous voulez d'une classe de type Enum (ci-après dénommée la classe Enum).
--Peut déclarer des constantes d'un type fixe --Si le type est décidé, l'achèvement dans l'EDI fonctionne.
Je voudrais créer une classe Enum qui répond aux exigences ci-dessus avec une classe qui définit une couleur appelée Color
.
Supposons qu'une constante a deux propriétés: name
, qui représente le nom de la couleur, et hex
, qui représente la couleur en hexadécimal.
Pour répondre à cette exigence, définissez un objet de classe Enum en tant que variable de classe Enum. Cela permet au type de constante d'être la classe Enum. Vous pouvez également forcer les déclarations de propriété en créant des objets via le constructeur.
class Color {
public static RED = new Color("red", "#ff0000")
public static GREEN = new Color("green", "#00ff00")
public static BLUE = new Color("blue", "#0000ff")
public constructor(
public name: string,
public hex: string,
) { }
}
Puisque les constantes sont des objets de la classe Color
, il n'y a pas de problème si vous déclarez une méthode d'instance comme une classe normale.
class Color {
public static RED = new Color("red", "#ff0000")
public static GREEN = new Color("green", "#00ff00")
public static BLUE = new Color("blue", "#0000ff")
public constructor(
public name: string,
public hex: string,
) { }
//Comparaison avec d'autres constantes
equals(other: Color) {
//Cette fois, les noms sont les mêmes
return this.name === other.name
}
//Représenter des constantes sous forme de chaînes
toString() {
return `${this.name}(${this.hex})`
}
//Définissez les méthodes requises ci-dessous
}
Avec le code ci-dessus, vous pouvez changer le «ROUGE» déclaré etc. de l'extérieur. Par conséquent, ajoutez le modificateur readonly
pour rendre l'objet immuable. En conséquence, si vous essayez de définir un nouvel objet dans Color.RED
ou Color.GREEN
déclaré comme une constante, une erreur de compilation se produira.
class Color {
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
public constructor(
public name: string,
public hex: string,
) { }
//Méthode de classe
//Méthode d'instance
}
L'immuabilité de la constante elle-même est garantie, mais les propriétés de la constante, «nom» et «hex», peuvent être modifiées. Par conséquent, rendez également la propriété immuable. Il y a deux manières d'y parvenir.
readonly
à la propriétéTout comme pour rendre la constante immuable, ajoutez readonly
à la propriété pour interdire le paramétrage. Cette méthode peut minimiser la quantité de description, mais «getter» est fixé par le nom de la propriété.
class Color {
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
public constructor(
public readonly name: string,
public readonly hex: string,
) { }
//Méthode de classe
//Méthode d'instance
}
private
et implémentez getter
Rendez la propriété invisible de l'extérieur et accédez-y via getter
. Cette méthode augmente la quantité de description, mais elle améliore la robustesse et la maintenabilité car vous pouvez décrire librement getter
sans accéder directement à la propriété.
class Color {
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
public constructor(
private _name: string,
private _hex: string,
) { }
//Lors de l'utilisation de get accessor
public get name() {
return this._name
}
//Comme un getter normal
public getName() {
return this._name
}
//Méthode de classe
//Méthode d'instance
}
Vous êtes libre de choisir lequel, mais cette fois, nous avons affaire à des constants et invariants, le premier semble donc approprié.
Pour répondre à cette exigence, rendez le constructeur invisible (private
) et interdisez la création d'objets de la classe Color
.
Maintenant, si vous essayez de créer un nouvel objet de classe Color
de l'extérieur, vous obtiendrez une erreur.
class Color {
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
private constructor(
public readonly name: string,
public readonly hex: string,
) { }
//Méthode de classe
//Méthode d'instance
}
Pensons à la réalisation de deux manières.
Comme pour les propriétés constantes, faites de la liste une variable de classe privée
afin qu'elle ne soit pas éditée de l'extérieur, et préparez votre propre getter
pour un accès de l'extérieur.
Pour ajouter à la liste, vous pouvez obtenir l'objet déclaré par this
dans le constructeur, nous allons donc l'ajouter.
Avec cette méthode, même si le nombre de constantes augmente, il n'est pas nécessaire de décrire la partie pour l'ajout de la liste, vous pouvez donc éviter d'oublier d'ajouter les constantes. Cependant, vous devez préparer votre propre getter
. (Si vous utilisez l'accesseur get pour getter
, il y a aussi un problème de chevauchement avec le nom de la propriété)
class Color {
private static _values = new Array<Color>()
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
private constructor(
public readonly name: string,
public readonly hex: string,
) {
Color._values.push(this)
}
public get values() {
return this._values
}
//Méthode de classe
//Méthode d'instance
}
Je ne sais pas s'il existe une scène d'utilisation, mais c'est un modèle pour déclarer la liste par vous-même.
Utilisez ʻimmutable.js pour rendre la liste immuable. ʻImmutable.js
est une belle bibliothèque pour déclarer facilement des listes et des cartes immuables. Une explication détaillée est ici
De cette façon, vous n'avez pas à polluer le constructeur pour ajouter une liste, et vous n'avez même pas besoin d'inclure un getter
pour l'accès externe, ce qui vous donne une meilleure vue de tout le code. Cependant, si le nombre de constantes augmente, il y a un problème que la partie décrite dans la liste gonfle, et il est facile d'oublier d'ajouter les constantes.
import { List } from 'immutable'
class Color {
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
public static readonly values = List.of(
Color.RED, Color.GREEN, Color.BLUE
)
private constructor(
public readonly name: string,
public readonly hex: string,
) { }
//Méthode de classe
//Méthode d'instance
}
J'aime celui à utiliser, mais cette fois, je vais utiliser celui à ajouter dans le constructeur.
Comme il s'agit d'une exigence pour une classe, nous définissons une méthode qui renvoie une constante comme méthode de classe.
class Color {
private static _values = new Array<Color>()
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
private constructor(
public readonly name: string,
public readonly hex: string,
) {
Color._values.push(this)
}
public get values() {
return this._values
}
//Obtenir la constante du nom
static fromName(name: string) {
return this.values.find(color => color.name === name)
}
//Méthode de classe
//Méthode d'instance
}
Le code jusqu'à présent peut être résumé comme suit.
class Color {
private static _values = new Array<Color>()
public static readonly RED = new Color("red", "#ff0000")
public static readonly GREEN = new Color("green", "#00ff00")
public static readonly BLUE = new Color("blue", "#0000ff")
private constructor(
public readonly name: string,
public readonly hex: string,
) {
Color._values.push(this)
}
static get values() {
return this._values
}
static fromName(name: string) {
return this.values.find(color => color.name === name)
}
equals(other: Color) {
return this.name === other.name
}
toString() {
return `${this.name}(${this.hex})`
}
}
Il y a aussi la question de l'effort nécessaire pour gérer les constantes, mais compte tenu de la maintenabilité et de l'extensibilité, je pense qu'il est très utile que l'inférence de type fonctionne et que des méthodes puissent être écrites. Voyons ensuite si nous pouvons écrire plus intelligemment en utilisant l'inférence de type.
Si vous avez des améliorations au code, n'hésitez pas à commenter.
L'explication de valueOf est ici. En un mot, cela signifie «rechercher par le nom de la constante déclarée et renvoyer la constante correspondante».
Essayons d'obtenir cela par la force en partant du principe que "les constantes sont toutes en majuscules".
Si vous n'avez pas besoin de filtrer, vous pouvez simplement l'obtenir avec Couleur [nom]
.
class Color {
//réduction
static valueOf(name: keyof typeof Color) {
if(/^[A-x]+$/.test(name)) {
return Color[name] as Color
}
return undefined
}
}
Mise en garde
Si vous l'obtenez avec Couleur [nom]
, vous obtiendrez une erreur de compilation si nom
ne correspond pas à la clé du type de couleur
. (Le haut est une erreur, le bas est OK)
Recommended Posts