ProgrammatieFrontend ontwikkelaar

Hoe werken toegangmodifiers (public, private, protected) in TypeScript? Wat zijn de nuances bij het gebruik ervan met overerving en bij de transpiling van code naar JavaScript?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord

In TypeScript worden toegangmodifiers gebruikt om de zichtbaarheid van eigenschappen en methoden in klassen te beperken:

  • public — eigenschap of methode is overal toegankelijk (standaard).
  • private — alleen toegankelijk in de class waar ze zijn gedeclareerd.
  • protected — toegankelijk in de class en zijn afgeleiden.
class Animal { public name: string; private age: number; protected kind: string; constructor(name: string, age: number, kind: string) { this.name = name; this.age = age; this.kind = kind; } } class Dog extends Animal { bark() { console.log(this.kind); // OK: protected // console.log(this.age); // Fout: private is niet zichtbaar in afgeleide class } } const dog = new Dog('Sharik', 5, 'zoogdier'); console.log(dog.name); // OK // console.log(dog.kind); // Fout: protected // console.log(dog.age); // Fout: private

Nuances:

  • In de gecompileerde JavaScript worden de modifiers private en protected alleen op compileertijd afgedwongen, er is geen fysieke isolatie in de runtime! De JS-code bevat alle eigenschappen (ze kunnen bijvoorbeeld worden verkregen via het doorlopen van het object).
  • In nieuwe versies (vanaf TypeScript 3.8) is er syntaxis geïntroduceerd voor echte private velden: #field, maar dit is al een JS-specificatie en wordt anders gecompileerd.

Trickvraag

Vraag: Is het mogelijk om toegang te krijgen tot een private eigenschap van een TypeScript-class na compilatie naar JavaScript?

Antwoord: Ja, omdat private (en protected) slechts een controle door TypeScript zijn op compileertijd, na compilatie naar ES5 of ES6 blijft de privacy niet behouden, de eigenschappen blijven in het object en zijn toegankelijk via naam-toegang (bijvoorbeeld via object['privateProp']).

// JS-code na compilatie function Animal(name, age, kind) { this.name = name; this.age = age; this.kind = kind; } var dog = new Animal('Sharik', 5, 'zoogdier'); console.log(dog['age']); // 5 — toegang is alleen op TS-niveau niet toegestaan!

Voorbeelden van echte fouten door onwetendheid over de nuances van het onderwerp.


Verhaal

In een groot project rekende de ontwikkelaar op de onbereikbaarheid van private velden in runtime. Als gevolg hiervan werden vertrouwelijke gegevens per ongeluk in de logboeken opgenomen bij het serialiseren van een object (JSON.stringify), omdat de TS-typing niet beschermde tegen werkelijke toegang tot de velden.


Verhaal

In het project werd een mechanisme gerealiseerd voor het "uitbreiden" van class-instanties door dynamisch eigenschappen toe te voegen. Dynamisch toegevoegde eigenschappen overschreven private namen, en ze werden per ongeluk gemanipuleerd door externe code. De fout werd pas op de productie ontdekt, waarbij de privacy niet werd gewaarborgd.


Verhaal

Bij de migratie van JavaScript naar TypeScript begon het team protected te gebruiken, denkend dat dit beschermde tegen het gebruik van velden buiten afgeleide klassen. Maar een programmeur overschreef per ongeluk het protected-veld in runtime via Object.assign, wat leidde tot een moeilijk te traceren bug. Dit was mogelijk omdat er geen runtime-inkapseling was.