Geschichte der Frage:
Der Symboltyp wurde in JavaScript (ES6) eingeführt, um eindeutige Identifikatoren zu erstellen, die garantiert nicht mit anderen Eigenschaften eines Objekts übereinstimmen. TypeScript unterstützt Symbole seit der Einführung der ES6-Kompatibilität.
Problem:
Vor der Einführung von Symbolen wurden häufig Strings als Schlüssel für Eigenschaften von Objekten verwendet. Dies führte zu Fehlern beim Erweitern oder Wiederverwenden von Objekten: zufällige Namenskonflikte und die Unmöglichkeit, private Eigenschaften (selbst durch Konvention) zu verbergen. Symbol ermöglichte es, eindeutige, für externen Code unsichtbare Schlüssel zu erstellen, aber es gab Fragen zur Typisierung — wie beschreibt man Typen mit Symbol-Schlüsseln und verwendet sie sicher in der API?
Lösung:
TypeScript unterstützt Symbole sowohl als Werte als auch als Typen, jedoch hat die Typisierung von Symbol-Schlüsseln ihre Besonderheiten. Um ein Symbol zu erstellen, kann der globale Konstruktor oder das globale Symbolregister verwendet werden. In Interfaces oder Typen müssen Schlüssel mit Symbolen den Typ explizit als symbol angeben, und der Zugriff auf solche Eigenschaften erfolgt nur über eine gespeicherte Referenz auf das Symbol.
Beispielcode:
const SECRET = Symbol('secret'); interface SecretObject { [SECRET]: string; visible: string; } const obj: SecretObject = { visible: 'see me', [SECRET]: 'hidden', }; console.log(obj.visible); // 'see me' // console.log(obj["secret"]); // Fehler: Eigenschaft existiert nicht! console.log(obj[SECRET]); // 'hidden'
Schlüsselmerkmale:
Kann ein Symbol automatisch in eine Zeichenkette umgewandelt werden, wenn es in Objekten verwendet wird?
Nein, ein Symbol kann nicht automatisch in eine Zeichenkette konvertiert werden. Ein Versuch, dies zu tun (z.B. durch Verkettung), führt zu einem Fehler.
const mySymbol = Symbol('desc'); // alert('prefix_' + mySymbol); // TypeError
Kann man Symbol-Schlüssel über Object.keys auflisten?
Nein, Object.keys und for...in ignorieren Symbol-Schlüssel. Um solche Schlüssel zu erhalten, wird Object.getOwnPropertySymbols verwendet.
const sym = Symbol('a'); const obj = { [sym]: 42 }; Object.keys(obj); // [] Object.getOwnPropertySymbols(obj); // [Symbol(a)]
Werden Eigenschaften mit Symbol-Schlüsseln beim Kopieren über Object.assign übertragen?
Ja, Object.assign kopiert sowohl String- als auch Symbol-Schlüssel, im Gegensatz zu JSON.stringify.
const s = Symbol('s'); const o1 = { [s]: 123, foo: 'bar' }; const o2 = Object.assign({}, o1); o2[s]; // 123
Ein Entwickler verwendete für private Eigenschaften String-Schlüssel ('_private'), in der Hoffnung auf Konvention. Im Team B wurde aus Versehen dieselbe Zeichenfolge hinzugefügt — die Eigenschaften überschrieben sich, und es trat ein unvorhersehbarer Fehler auf.
Vorteile:
Nachteile:
Ein zweiter Entwickler verwendete Symbol für versteckte Eigenschaften (zum Beispiel Symbol('internal')). Jetzt können selbst innerhalb des Teams interne Daten nicht versehentlich überschrieben werden: der Zugriff ist nur möglich, wenn eine Referenz auf ein bestimmtes Symbol vorhanden ist.
Vorteile:
Nachteile: