Achtergrond:
Type Symbol werd toegevoegd aan JavaScript (ES6) voor het creëren van unieke identificators die gegarandeerd niet in conflict komen met andere eigenschappen van objecten. TypeScript ondersteunt symbolen sinds de invoering van ES6-compatibiliteit.
Probleem:
Voor de introductie van Symbol werden vaak strings gebruikt als sleutels voor objecteigenschappen. Dit leidde tot fouten bij het uitbreiden of hergebruiken van objecten: willekeurige naamconflicten en het onvermogen om privé-eigenschappen te verbergen (zelfs via conventie). Symbol stelde gebruikers in staat om unieke, voor externen onzichtbare sleutels te creëren, maar er ontstonden vragen over typisering: hoe beschrijf je types met Symbol-sleutels en gebruik je ze veilig in een API?
Oplossing:
TypeScript ondersteunt symbolen als waarden en types, maar de typisering van Symbol-sleutels heeft enkele kenmerken. Voor het maken van een symbool kan de globale constructor of de globale registersymbolen worden gebruikt. In interfaces of types moeten sleutels met symbolen het type expliciet als symbol opgeven, en toegang tot dergelijke eigenschappen gebeurt alleen met een opgeslagen verwijzing naar het Symbol.
Codevoorbeeld:
const SECRET = Symbol('secret'); interface SecretObject { [SECRET]: string; visible: string; } const obj: SecretObject = { visible: 'zie mij', [SECRET]: 'verborgen', }; console.log(obj.visible); // 'zie mij' // console.log(obj["secret"]); // Fout: zo'n eigenschap bestaat niet! console.log(obj[SECRET]); // 'verborgen'
Belangrijkste kenmerken:
Kan een Symbol automatisch naar een string worden geconverteerd bij het gebruik in objecten?
Nee, een Symbol kan niet automatisch worden geconverteerd naar een string; een poging om dit te doen (bijvoorbeeld via concatenatie) leidt tot een fout.
const mySymbol = Symbol('desc'); // alert('prefix_' + mySymbol); // TypeError
Kun je Symbol-sleutels enumereren met Object.keys?
Nee, Object.keys en for...in negeren Symbol-sleutels. Voor het verkrijgen van dergelijke sleutels wordt Object.getOwnPropertySymbols gebruikt.
const sym = Symbol('a'); const obj = { [sym]: 42 }; Object.keys(obj); // [] Object.getOwnPropertySymbols(obj); // [Symbol(a)]
Worden eigenschappen met Symbol-sleutels gekopieerd bij gebruik van Object.assign?
Ja, Object.assign kopieert zowel string- als symbolische sleutels, in tegenstelling tot JSON.stringify.
const s = Symbol('s'); const o1 = { [s]: 123, foo: 'bar' }; const o2 = Object.assign({}, o1); o2[s]; // 123
Een ontwikkelaar gebruikte string-sleutels voor privé-eigenschappen ('_private'), vertrouwend op conventie. In Team B werd per ongeluk dezelfde string toegevoegd — de eigenschappen werden overschreven, en er ontstond een onvoorspelbare fout.
Voordelen:
Nadelen:
Een tweede ontwikkelaar gebruikte Symbol voor verborgen eigenschappen (bijvoorbeeld Symbol('internal')). Nu kan zelfs binnen het team per ongeluk interne gegevens niet worden overschreven: toegang is alleen mogelijk met een verwijzing naar een specifieke Symbol.
Voordelen:
Nadelen: