Historia pytania
W TypeScript prywatne właściwości pojawiły się początkowo za pomocą modyfikatora private, a począwszy od ECMAScript 2021 w JavaScript wspierane są prawdziwe prywatne pola za pomocą symbolu #. Główna zasada — inkapsulacja danych, aby chronić wewnętrzne szczegóły klasy przed dostępem z zewnątrz.
Problem
Modyfikator private w TypeScript zapewnia prywatność tylko na etapie kompilacji, ale w skompilowanym JavaScript te pola są dostępne poprzez bezpośredni dostęp do właściwości obiektu. Może to prowadzić do niezamierzonej zmiany stanu obiektu. Pola prywatne ES (#) są całkowicie niedostępne poza klasą nawet na poziomie czasu wykonywania JS, co zapewnia rzeczywistą ochronę danych.
Rozwiązanie
TypeScript obsługuje oba podejścia. Wybierając między nimi, kieruj się wymaganą stopą ochrony i ograniczeniami kompatybilności z wersjami JS.
Przykład kodu:
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 — błąd w TS, ale zadziała przez x['hidden'] w JS // x.#trulyHidden — błąd składniowy nawet w JS
Kluczowe cechy:
private zapewnia prywatność tylko na etapie kompilacji TypeScript#field zapewnia prawdziwą prywatność na poziomie wykonania JavaScript# wymaga wsparcia nowoczesnego JS (ES2021+)Czy można uzyskać dostęp do prywatnego pola klasy TypeScript poprzez bezpośrednie odwołanie w JS?
Tak, można, ponieważ prywatność jest implementowana tylko na etapie kompilacji. W pierwotnym JS pole będzie zwykłą właściwością obiektu. Na przykład:
class A { private x = 1; } const a = new A(); console.log((a as any)["x"]); // 1
Czy można używać prywatnych pól z # w interfejsach lub opisywać je za pomocą type?
Nie, pola #private są częścią tylko implementacji klasy i nie mogą być opisane w interfejsach, typach ani używane poza samą klasą. Interfejsy opisują tylko publiczne człony.
Czy można dziedziczyć prywatne pola zadeklarowane za pomocą #?
Nie, takie pola są całkowicie niedostępne dla klas dziedziczących. Tylko sama klasa ma do nich dostęp:
class Parent { #foo = 123; } class Child extends Parent { // this.#foo = 444; // Błąd }
private do ochrony krytycznych danych — prowadzi do podatności na bezpośredni dostępW projekcie do przechowywania haseł w klasie User użyto pola private password. Jeden z programistów przypadkowo uzyskuje dostęp przez user['password'] do debugowania, a pole okazuje się być zmienione przez zewnętrzny moduł.
Zalety:
Wady:
Programista używa ES prywatnego pola #password. Teraz próby odwołania się do pola poprzez indeksowanie czy w dziedziczących klasach nie przechodzą, bezpieczeństwo danych jest zapewnione nawet przy użyciu zewnętrznych bibliotek i narzędzi.
Zalety:
Wady: