Modyfikatory dostępu w klasach

TIP: Cały kod do poszczególnych lekcji, dodatkową teorię i linki z tej i innych lekcji - znajdziesz w darmowym repozytorium - https://github.com/jaktestowac/typescript-dla-testera Chcesz dokładniej poznać TypeScript? Sprawdź nasz Program JavaScript i TypeScript dla Testerów

Prezentacja

Tu w przyszłości mogą pojawić się dodatkowe materiały w postaci prezentacji etc.

Dodatkowe materiały

Modyfikatory dostępu określają, skąd możesz odczytać/zaktualizować pole lub wywołać metodę klasy.
W TypeScript masz: public (domyślnie), private, protected oraz kwalifikator readonly.
Dodatkowo istnieją prywatne pola ECMAScript z #nazwa (egzekwowane w runtime).

public (domyślne) i readonly

// public is default; readonly prevents reassignment after init
class Product {
  readonly id: number;     // can be set once
  name: string;            // public by default


  constructor(id: number, name: string) {
    this.id = id;          // OK (initialization)
    this.name = name;
  }
}


const p = new Product(1, 'Book');
// p.id = 2; // ❌ Error: cannot assign to 'id' because it is a read-only property
p.name = 'Notebook';       // ✅ OK
  

private – tylko wewnątrz klasy

// 'private' members are only accessible inside the class
class Counter {
  private value = 0;


  increment() {
    this.value++;
  }


  current() {
    return this.value;
  }
}


const c = new Counter();
c.increment();
console.log(c.current()); // 1
// console.log(c.value);  // ❌ Error: 'value' is private
  

protected – dla klasy i klas pochodnych

// 'protected' is visible in subclasses
class User {
  protected role: string = 'user';


  isAdmin(): boolean {
    return this.role === 'admin';
  }
}


class AdminUser extends User {
  promote() {
    this.role = 'admin'; // ✅ allowed in subclass
  }
}


const u = new AdminUser();
u.promote();
console.log(u.isAdmin()); // true
// console.log(u.role);   // ❌ Error: 'role' is protected
  
Parameter properties – skrót deklaracji pól

// TS shortcut: visibility modifiers in constructor params
class Person {
  constructor(
    public name: string,
    private age: number,
    public readonly id: number
  ) {}
  info() { return `${this.name} (${this.id})`; }
}


const person = new Person('Ala', 30, 101);
console.log(person.info()); // "Ala (101)"
// console.log(person.age); // ❌ private
// person.id = 202;        // ❌ readonly
  

Linki zewnętrzne

4 komentarze

  1. odnośnie ramki “dla dociekliwych”, po dodaniu w kodzie:

    user.setPassword(“wrongPassword”, “anotherSecurePassword”) // Old password is incorrect!
    user.password = “wrongPassword”
    user.setPassword(“wrongPassword”, “anotherSecurePassword”)
    ta ostatnia zmiana hasła działa, tzn
    Password updated successfully.
    Old password is incorrect.
    Password updated successfully.

    Czy dzieje się tak, bo modyfikatory nie są “twardo” egzekwowane przed ES2022?
    Czy jedynym lekarstwem jest używanie “prawdziwego” modyfikatora private, np. #password / this.#password?

    Avatar Dominik Witkiewicz
    1. Świetna pytanie i dokładnie tak to działa 😉 To, co widzisz, wynika z faktu, że private w TypeScript działa tylko na etapie kompilacji, a nie w runtime. Po wygenerowaniu JavaScriptu pole password jest zwykłą właściwością obiektu, więc można je nadpisać z zewnątrz, omijając logikę metody setPassword.

      Dlatego po ręcznym przypisaniu:

      user.password = "wrongPassword"
      

      kolejne wywołanie:

      user.setPassword("wrongPassword", "anotherSecurePassword")
      

      działa poprawnie, bo warunek porównania już się zgadza.

      Jeśli zależy nam na prawdziwej enkapsulacjito należy użyć prywatnych pól JavaScript:

      #password
      

      które są rzeczywiście ukryte i nie da się ich zmodyfikować spoza klasy 🙂

      1. Dobry tip bo npx tsx faktycznie uruchamia kod bez pełnego sprawdzenia typów, więc może przepuścić błędy, które tsc by zgłosił. Dokumentacja tsx wprost mówi, że narzędzie nie wykonuje samodzielnie sprawdzania typów i zakłada, że robimy to osobno, np. przez tsc –noEmit albo w IDE.
        Natomiast w tym przykładzie to nie tsx jest sednem problemu. Nawet gdybyś uruchomił kod po pełnym sprawdzeniu TypeScript, private w TypeScript i tak nie daje pełnej ochrony 🙂

        W dokumentacji TypeScript znajdziemy ze jesli potrzebujemy pełnej prywatności dla pól to należy użyć mechanizmów takich jak private fields z # 🙂

        https://www.typescriptlang.org/docs/handbook/2/classes.html#caveats

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *