Ich bin einsam mit dem TypeScript-Adventskalender, daher stelle ich vor, was ich zuvor geschrieben habe.
Enum gibt es auch in Typescript, aber ich bin nicht gut darin, Funktionen zu definieren oder mehrere Werte zusammen zu behandeln. (Mit Namespace
können Sie nichts anfangen.](Https://qiita.com/ConquestArrow/items/5d885128f896844698dd#%E9%96%A2%E6%95%B0%E3%82%84enum%E3 % 82% 92% E6% 8B% A1% E5% BC% B5))
Normalerweise benutze ich Java. Als ich mich mit Typescript beschäftigte, wollte ich so etwas wie Javas Enum.
Also habe ich versucht, etwas wie Javas Enum in einer Klasse mit Typescript auszudrücken. (So ähnlich)
Ich bin mir sicher, dass es Leute gibt, die das für selbstverständlich halten, auch wenn es ihnen nicht gesagt wird, aber ich werde es anstelle meiner eigenen Notizen belassen.
Lassen Sie uns zunächst auflisten, was Sie von einer Enum-ähnlichen Klasse wollen (im Folgenden als Enum-Klasse bezeichnet).
--Kann Konstanten eines festen Typs deklarieren
Ich möchte eine Enum-Klasse erstellen, die die oben genannten Anforderungen mit einer Klasse erfüllt, die eine Farbe namens "Farbe" definiert. Angenommen, eine Konstante hat zwei Eigenschaften: "Name", der den Namen der Farbe darstellt, und "Hex", der die Farbe in Hexadezimalzahl darstellt.
Um diese Anforderung zu erfüllen, definieren Sie ein Objekt der Klasse Enum als Enum-Klassenvariable. Dadurch kann der Konstantentyp die Enum-Klasse sein. Sie können Eigenschaftsdeklarationen auch erzwingen, indem Sie Objekte über den Konstruktor erstellen.
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,
) { }
}
Da Konstanten Objekte der Klasse Color
sind, gibt es kein Problem, wenn Sie eine Instanzmethode wie eine normale Klasse deklarieren.
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,
) { }
//Vergleich mit anderen Konstanten
equals(other: Color) {
//Diesmal sind die Namen gleich
return this.name === other.name
}
//Konstanten als Zeichenfolgen darstellen
toString() {
return `${this.name}(${this.hex})`
}
//Definieren Sie unten die erforderlichen Methoden
}
Mit dem obigen Code können Sie das deklarierte "ROT" usw. von außen ändern. Fügen Sie daher den Modifikator "readonly" hinzu, um das Objekt unveränderlich zu machen. Wenn Sie versuchen, ein neues Objekt in "Color.RED" oder "Color.GREEN" als Konstante zu deklarieren, tritt ein Kompilierungsfehler auf.
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,
) { }
//Klassenmethode
//Instanzmethode
}
Die Unveränderlichkeit der Konstante selbst ist garantiert, aber die Eigenschaften der Konstanten "Name" und "Hex" können geändert werden. Machen Sie daher die Immobilie auch unveränderlich. Es gibt zwei Möglichkeiten, dies zu erreichen.
Fügen Sie der Eigenschaft genau wie beim Ändern der Konstanten "readonly" hinzu, um das Setzen zu verhindern. Diese Methode kann den Umfang der Beschreibung minimieren, aber getter
wird durch den Eigenschaftsnamen festgelegt.
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,
) { }
//Klassenmethode
//Instanzmethode
}
Machen Sie die Immobilie von außen unsichtbar und greifen Sie über getter
darauf zu. Diese Methode erhöht den Umfang der Beschreibung, verbessert jedoch die Robustheit und Wartbarkeit, da Sie "Getter" frei beschreiben können, ohne direkt auf die Eigenschaft zuzugreifen.
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,
) { }
//Bei Verwendung von get accessor
public get name() {
return this._name
}
//Wie ein normaler Getter
public getName() {
return this._name
}
//Klassenmethode
//Instanzmethode
}
Sie können eine der beiden auswählen, aber diesmal haben wir es mit konstanten und invarianten zu tun, so dass die erstere angemessen erscheint.
Um diese Anforderung zu erfüllen, machen Sie den Konstruktor unsichtbar ("privat") und verbieten Sie die Erstellung von Objekten der Klasse "Farbe". Wenn Sie nun versuchen, ein neues Objekt der Klasse "Farbe" von außen zu erstellen, wird eine Fehlermeldung angezeigt.
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,
) { }
//Klassenmethode
//Instanzmethode
}
Lassen Sie uns die Realisierung auf zwei Arten betrachten.
Machen Sie die Liste wie bei konstanten Eigenschaften zu einer "privaten" Klassenvariablen, damit sie nicht von außen bearbeitet wird, und bereiten Sie Ihren eigenen "Getter" für den Zugriff von außen vor.
Um der Liste etwas hinzuzufügen, können Sie das durch this
deklarierte Objekt im Konstruktor abrufen, also werden wir dies hinzufügen.
Selbst wenn die Anzahl der Konstanten zunimmt, ist es bei dieser Methode nicht erforderlich, den Teil zum Hinzufügen der Liste zu beschreiben, damit Sie nicht vergessen, die Konstanten hinzuzufügen. Sie müssen jedoch Ihren eigenen "Getter" vorbereiten. (Wenn Sie den get-Accessor für "getter" verwenden, besteht auch das Problem der Überlappung mit dem Eigenschaftsnamen.)
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
}
//Klassenmethode
//Instanzmethode
}
Ich weiß nicht, ob es eine Nutzungsszene gibt, aber es ist ein Muster, die Liste selbst zu deklarieren.
Verwenden Sie immutable.js
, um die Liste unveränderlich zu machen.
immutable.js
ist eine nette Bibliothek zum einfachen Deklarieren unveränderlicher Listen und Karten. Eine ausführliche Erklärung finden Sie hier.
Auf diese Weise müssen Sie den Konstruktor nicht verschmutzen, um eine Liste hinzuzufügen, und Sie müssen nicht einmal einen "Getter" für den externen Zugriff einfügen, wodurch Sie den gesamten Code besser sehen können. Wenn jedoch die Anzahl der Konstanten zunimmt, tritt das Problem auf, dass sich der in der Liste beschriebene Teil ausbaucht, und es ist leicht zu vergessen, die Konstanten hinzuzufügen.
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,
) { }
//Klassenmethode
//Instanzmethode
}
Ich mag, welche ich verwenden soll, aber dieses Mal werde ich die verwenden, um sie im Konstruktor hinzuzufügen.
Da dies eine Voraussetzung für eine Klasse ist, definieren wir eine Methode, die eine Konstante als Klassenmethode zurückgibt.
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
}
//Holen Sie sich Konstante vom Namen
static fromName(name: string) {
return this.values.find(color => color.name === name)
}
//Klassenmethode
//Instanzmethode
}
Der bisherige Code kann wie folgt zusammengefasst werden.
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})`
}
}
Es gibt auch die Frage, wie viel Aufwand für den Umgang mit Konstanten erforderlich ist. Angesichts der Wartbarkeit und Erweiterbarkeit halte ich es jedoch für sehr nützlich, dass Typinferenz funktioniert und Methoden geschrieben werden können. Als nächstes überlegen wir, ob wir mit Typinferenz intelligenter schreiben können.
Wenn Sie Verbesserungen am Code haben, können Sie dies gerne kommentieren.
Die Erklärung von valueOf lautet hier. Kurz gesagt bedeutet dies "Suche nach dem deklarierten Konstantennamen und Rückgabe der passenden Konstante".
Versuchen wir, dies mit Gewalt unter der Prämisse zu erreichen, dass "Konstanten alle in Großbuchstaben geschrieben sind". Wenn Sie nicht filtern müssen, können Sie es einfach mit "Farbe [Name]" abrufen.
class Color {
//Kürzung
static valueOf(name: keyof typeof Color) {
if(/^[A-x]+$/.test(name)) {
return Color[name] as Color
}
return undefined
}
}
Hinweis
Wenn Sie es mit "Farbe [Name]" erhalten, wird ein Kompilierungsfehler angezeigt, wenn "Name" nicht mit dem "Schlüssel des Farbtyps" übereinstimmt. (Die Oberseite ist ein Fehler, die Unterseite ist in Ordnung)
Recommended Posts