Modyfikatory dostępu TypeScript

W porzednim wpisie ogólnie dowiedzieliśmy się do czego przydadzą się nam modyfikatory dostępu. W tym przejdzemy do konkretów czyli omówienia poziomów dostępu oferowanych prez TypeScript – public, private i protected.


Zapraszam do dołączenia za darmo do kilkugodzinnego kursu wprowadzającego do TypeScript.


Modyfikatory dostępu w TypeScript – rodzaje

TypeScript wspiera trzy typy modyfikatorów dostępu – public, private i protected. Używamy ich przed nazwami zmiennych bądź funkcji.

class Info {
    
  private name: string;
  private email: string;
  private preferences: string[];

  constructor(name: string, email: string) {
      this.name = name;
      this.email = email;
      this.preferences = [];
  }

  public toString = () => {
     return `${this.name} - ${this.email}`;
  };
}

Domyślnym z nich jest public, więc linijka

constructor(name: string, email: string)

tłumaczy się na

public constructor(name: string, email: string)

Public

Public jest najszerszym modyfikatorem dostępu, umożliwia on dostęp do tak oznaczonego elementu wszystkim i wszystkiemu. Jest to, jak już wspominałem, domyślny poziom dostępu. Jest to też jedyny poziom dostępu w JavaScript, gdzie wszystko jest publiczne.

Poniższy kod wykona się więć bez żadnego problemu:

class Info {
    
  public name: string;
  public email: string;
  public preferences: string[];

  constructor(name: string, email: string) {
      this.name = name;
      this.email = email;
      this.preferences = [];
  }

  public toString = () => {
    return `${this.name} - ${this.email}`;
  };
}

class ClassifiedInfo extends Info {
  public toString = () => {
    return `${super.name}. Everything else is classified`;
  }
}

let info : Info = new Info("Pawel", "pawel@pawel");
console.log(info.name);
info.email = "nowy@gmail";
console.log(info.toString());

Do zmiennych email, name oraz metody toString jest dostęp z poziomu klasy definiującej te pola (Info), jak i klasy rozszerzającej klasę Info (ClassifiedInfo) oraz dodatkowo z globalnego scope aplikacji.

Protected

Modyfikator protected ucina nieco swawole wyczyniające się dzięki public. Do elementów tak oznaczonych ma dostęp tylko klasa, w której zostały one zdefiniowane oraz wszelkie klasy dziedziczące po niej.

class Info {
    
  protected name: string;
  protected email: string;
  protected preferences: string[];

  constructor(name: string, email: string) {
      this.name = name;
      this.email = email;
      this.preferences = [];
  }

  protected toString = () => {
    return `${this.name} - ${this.email}`;
  };
}

class ClassifiedInfo extends Info {
  public toString = () => {
    return `${super.name}. Everything else is classified`;
  }
}

let info : Info = new Info("Pawel", "pawel@pawel");
console.log(info.name);
info.email = "nowy@gmail";
console.log(info.toString());

Dostęp do pól z poziomu klasy Info i ClassifiedInfo jest wciąż dozwolony, ponieważ ClassifiedInfo jest dzieckiem klasy Info. Natomiast wywołania w przestrzeni globalnej wywołają błędy kompilatora.

Private

Private jest ostatnim z modyfikatorów dostępu w TypeScript i jest niemal lustrzanym odbiciem public. Do elementów określonych jako private dostęp jest tylko z poziomu klasy, która je deklaruję. Natomiast dostęp z klas potomnych czy przestrzeni globalnej wywoła płacz kompilatora.

class Info {
    
  private name: string;
  private email: string;
  private preferences: string[];

  constructor(name: string, email: string) {
      this.name = name;
      this.email = email;
      this.preferences = [];
  }

  private toString = () => {
    return `${this.name} - ${this.email}`;
  };
}

class ClassifiedInfo extends Info {
  public toString = () => {
    return `${super.name}. Everything else is classified`;
  }
}

let info : Info = new Info("Pawel", "pawel@pawel");
console.log(info.name);
info.email = "nowy@gmail";
console.log(info.toString());

Przy tak określonym dostępie zarówno w przestrzeni globalnej, jak i w klasie ClassifiedInfo pojawią się błędy kompilacji, w klasie Info nadal wszystko będzie w porządku.

Jak używać modyfikatorów dostępu

Oczywiście robienie wszystkiego prywatnym bądź publicznym to nie jest rozwiązanie.

Najprostszym podejściem do problemu “jakiego modyfikatora dostępu użyć” jest następujący algorytm:

  1. Stan klasy zawsze jest prywatny.
  2. Konstruktor jest publiczny.
  3. Metody używane przez inne klasy są publiczne, natomiast wszelkie metody pomocnicze (tzn. takie używane przez implementacje metody publicznej) są prywatne.
  4. Jeśli musimy wystawić na zewnątrz możliwość pobrania/zmiany stanu robimy to poprzez getter/setter
class DataTransformer {

    private data: string;
    private reversed: string[];
    private transformed: string;

    constructor(data: string) {
       this.data = data;
       this.reversed = [];
       this.transformed = "";
    }

    private splitData() : void {
       this.reversed = this.data.split("");
    }

    private reverseData() : void {
       this.reversed = this.reversed.reverse();
    }

    private joinData() : void {
       this.transformed = this.reversed.join("");       
    }

    public transform() : string {
       this.splitData(); 
       this.reverseData();
       this.joinData();
       return this.transformed;  
    }
}

const trans : DataTransformer = new DataTransformer("hello");
console.log(trans.transform());

Oczywiście jak do wszystkiego jest masa wyjątków od tego prostego podejścia, ale na start jest w zupełności wystarczające.

Runtime

W trakcie działania aplikacji mamy do czynienia z JavaScript, więc niestety modyfikatory dostępu giną i wszystko jest publiczne.

Zapraszam do dołączenia do newslettera

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *