Créez quelque chose comme Enum de Java avec Typescript

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.

Exigences d'énumération

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.

code

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.

Peut déclarer des constantes d'un type fixe

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,
  ) { }
}

Vous pouvez ajouter des méthodes aux constantes

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
}

La constante est invariante

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.

Ajouter 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
}

Définissez la propriété sur 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é.

Vous ne pouvez pas ajouter de constantes de l'extérieur

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
}

Vous pouvez obtenir une liste des constantes déclarées dans un état immuable

Pensons à la réalisation de deux manières.

Ajouter à la liste du constructeur

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
}

Ajouter à la liste vous-même

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.

Vous pouvez obtenir une constante à partir d'une variable donnée

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

}

Résumé

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.

prime

Atteindre la valeur Java

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)

image.png

Recommended Posts

Créez quelque chose comme Enum de Java avec Typescript
[Java] Énumération des branches avec instruction switch
[Java] Réduire les instructions if avec Enum
Créez une énumération haute performance avec des champs et des méthodes comme Java avec JavaScript
[Java] enum (type d'énumération)
Interface Essayez de créer un problème Java TypeScript 7-3
Implémenter quelque chose comme une pile en Java
[Java] Rendez le programme 10 fois plus rapide avec parallelStream
[First Java] Créez quelque chose qui fonctionne avec Intellij pour le moment
J'ai essayé de faire une authentification de base avec Java
Rendre l'environnement SpringBoot1.5 + Gradle4.4 + Java8 + Docker compatible avec Java11
[Java] Créez quelque chose comme une API de recherche de produits
Comportement incrémenté Essayez de créer un problème Java TypeScript 3-4
Opération de chaîne de caractères Essayez de changer le problème Java en TypeScript 9-3
Quelque chose à propos de java
Couverture de code Java plus confortable avec Jacoco 0.8.0
Rendre la ligne Java Stream agréable avec Eclipse
Facile à créer LINE BOT avec Java Servlet
Je veux faire quelque chose comme "cls" en Java
Initialisation de for Essayez de changer le problème Java en TypeScript 5-4
Rendre les gadgets de calendrier créés avec JavaFX compatibles avec Java SE 9
[Bases de Java] Créons un triangle avec une instruction for
Implémentez rapidement singleton avec enum en Java
Faites quelque chose de sharding avec Abstract Routing DataSource de Spring!
J'avais l'habitude de faire nc (netcat) avec JAVA normalement
Installez java avec Homebrew
Faites un blackjack avec Java
Changer de siège avec Java
Installez Java avec Ansible
Téléchargement confortable avec JAVA
Changer java avec direnv
Enum Reverse Map Java
Téléchargement Java avec Ansible
Raclons avec Java! !!
Construire Java avec Wercker
Conversion Endian avec JAVA
[Débutant] Essayez de créer un jeu RPG simple avec Java ①
Je veux faire une liste avec kotlin et java!
Je veux créer une fonction avec kotlin et java!
Étudiez Java: utilisez Timer pour créer quelque chose comme un minuteur de bombe