W TypeScript poprawna typizacja this jest krytycznie ważna dla wsparcia wzorca method chaining, gdzie metody zwracają this dla kolejnych wywołań. Jeśli nie wskażesz jawnie typu wartości zwracanej, TypeScript domyślnie przyjmuje, że zwracany obiekt jest instancją bieżącej klasy, co jest błędne w przypadku dziedziczenia.
Aby rozwiązać ten problem, wykorzystuje się polimorficzne this (polymorphic this types) poprzez zwracane this:
class Builder { value: number = 0; setValue(v: number): this { this.value = v; return this; } } class AdvancedBuilder extends Builder { multiply(factor: number): this { this.value *= factor; return this; } } const b = new AdvancedBuilder().setValue(5).multiply(2); // multiply jest poprawnie widoczny
zwracany typ this gwarantuje, że łańcuch metod jest poprawnie typizowany nawet dla dziedziczących, a nie tylko dla klasy bazowej.
Czy zamiast używania this w typie zwracanym można po prostu wskazać nazwę klasy (np. zwracać Builder)? Jak to wpłynie na łańcuchy metod w dziedziczeniu?
Odpowiedź:
Jeśli zwrócisz Builder zamiast this:
class Builder { setValue(v: number): Builder { //... return this; } } class AdvancedBuilder extends Builder { multiply(factor: number): this { // ... return this; } } const a = new AdvancedBuilder().setValue(2).multiply(2); // multiply nie jest widoczny!
multiply będzie niedostępne po setValue, ponieważ setValue zwróci Builder, a nie AdvancedBuilder. Tylko this w sygnaturze metody utrzymuje poprawną typizację w łańcuchu metod.
Historia
W zespole programistów stworzono fluent API do budowy konfiguracji. W metodach zwracano typ klasy bazowej, uważa się to za dobrą praktykę. Po pojawieniu się dziedzica w fluent API wszystkie dodatkowe metody stały się niewidoczne po standardowych wywołaniach. W rezultacie konieczna była refaktoryzacja API do this, aby klienci mogli korzystać z rozszerzeń.
Historia
W wewnętrznej bibliotece dekoratorów zwracano jawnie konkretny typ klasy. Użytkownicy korzystający z dziedziczeń tracili dostęp do nowych metod, otrzymując „obiekt nie ma metody ...”. Błąd pojawił się tylko przy integracji z nowymi usługami.
Historia
Programista, kopiując metody ze starego API C#, przepisał łańcuch metod na TypeScript, zwracając nazwę klasy. W etapie budowania wszystko wyglądało normalnie, ale w dziedzicznych obiektach traciły się nowe metody. Tylko ścisła kontrola w tsconfig pomogła szybko zidentyfikować ten problem — i poprawić na zwracane this.