Storia della questione
In TypeScript, le proprietà private sono state introdotte inizialmente tramite il modificatore private, mentre a partire da ECMAScript 2021 in JavaScript sono supportati i veri campi chiusi attraverso il simbolo #. L'obiettivo principale è l'incapsulamento dei dati, al fine di proteggere i dettagli interni della classe dall'accesso esterno.
Problema
Il modificatore private in TypeScript garantisce la privacy solo a livello di compilazione, ma nel JavaScript compilato questi campi rimangono accessibili tramite accesso diretto alle proprietà dell'oggetto. Questo può portare a modifiche indesiderate dello stato dell'oggetto. I Campi Privati ES (#) sono completamente inaccessibili al di fuori della classe anche a livello di runtime JS, fornendo così una vera protezione dei dati.
Soluzione
TypeScript supporta entrambi gli approcci. Quando si sceglie tra di essi, è importante orientarsi sul grado di protezione necessario e sulle limitazioni di compatibilità con le versioni JS.
Esempio di codice:
class Example { private hidden: number; #trulyHidden: string; constructor() { this.hidden = 42; this.#trulyHidden = 'secret'; } getHidden() { return this.hidden; } getTrulyHidden() { return this.#trulyHidden; } } const x = new Example(); // x.hidden — errore in TS, ma funziona tramite x['hidden'] in JS // x.#trulyHidden — errore di sintassi anche in JS
Caratteristiche chiave:
private garantisce la privacy solo a livello di compilazione di TypeScript#field fornisce una vera privacy a livello di esecuzione in JavaScript# richiede il supporto di un JavaScript moderno (ES2021+)È possibile accedere a un campo privato di una classe TypeScript tramite accesso diretto in JS?
Sì, è possibile, poiché la privacy è implementata solo a livello di compilazione. Nel JS sorgente, il campo sarà una normale proprietà dell'oggetto. Ad esempio:
class A { private x = 1; } const a = new A(); console.log((a as any)["x"]); // 1
È possibile utilizzare campi privati con # nelle interfacce o descriverli tramite type?
No, i campi #private sono parte solo dell'implementazione della classe e non possono essere descritti nelle interfacce, nei tipi o utilizzati al di fuori della classe stessa. Le interfacce descrivono solo membri pubblici.
È possibile ereditare campi privati, dichiarati con #?
No, tali campi non sono affatto accessibili alle classi figlie. Solo la classe stessa ha accesso ad essi:
class Parent { #foo = 123; } class Child extends Parent { // this.#foo = 444; // Errore }
private per proteggere dati critici — porta a vulnerabilità con accesso direttoNel progetto per la memorizzazione delle password nella classe User è stato utilizzato il campo private password. Uno degli sviluppatori ottiene accidentalmente accesso tramite user['password'] per il debugging, e il campo viene modificato da un modulo esterno.
Vantaggi:
Svantaggi:
Lo sviluppatore utilizza il campo privato ES #password. Ora i tentativi di accesso al campo tramite indicizzazione o nelle classi figlie non sono consentiti, la sicurezza dei dati è garantita anche con l'uso di librerie e strumenti di terze parti.
Vantaggi:
Svantaggi: