Historia pytania
Wiele ściśle typowanych języków (C++, C#, Python) pozwala na wyraźne opisanie przeciążeń dla operatorów (np. +, -, *, ==) na poziomie klasy. W TypeScript, podobnie jak w JavaScript, przeciążanie operatorów nie występuje na poziomie języka z powodów historycznych i architektonicznych.
Problem
Gdy trzeba dodać wsparcie dla arytmetyki lub innych operacji dla złożonych typów (np. liczb zespolonych lub wektorów), nie można zmienić standardowych operatorów. Ogranicza to ekspresyjność i wymaga wynajdywania obejść.
Rozwiązanie
W TypeScript symuluje się przeciążenie operatorów przez specjalnie nazwane metody (np. add, equals, multiply). Wyposażając klasę w takie metody, realizujemy typowozabezpieczone zachowanie, chociaż składnia nie jest tak zwięzła jak w C++.
Przykład kodu:
class Vector { constructor(public x: number, public y: number) {} add(other: Vector): Vector { return new Vector(this.x + other.x, this.y + other.y); } equals(other: Vector): boolean { return this.x === other.x && this.y === other.y; } } const a = new Vector(1, 2); const b = new Vector(3, 4); const c = a.add(b); // Vector { x: 4, y: 6 } const eq = a.equals(b); // false
Kluczowe cechy:
Czy można nadpisać działanie operatora "==" lub "+" dla własnej klasy w TypeScript?
Nie, JavaScript (i TypeScript) nie pozwala bezpośrednio na przeciążanie standardowych operatorów dla obiektów użytkowników. Operatory są stosowane ściśle zgodnie ze standardem dla Object, Number i innych prymitywów. Jakakolwiek próba takiego "nadpisania" prowadzi do nieprawidłowego lub nieprzewidywalnego zachowania lub po prostu nie działa.
Czy można użyć valueOf lub toString do pośredniego wpływu na operatory?
W niektórych przypadkach można użyć valueOf (np. do skróconej konwersji na liczbę), ale tylko dla operatorów, które odnoszą się do prymitywnej wartości obiektu.
class Box { constructor(private v: number) {} valueOf() { return this.v; } } const a = new Box(10); console.log(a + 5); // 15 — działa, ale dla złożonych obiektów jest nieintucyjne
Jednak dla złożonych struktur i operatorów logicznych sensowne jest używanie jawnych metod.
Czy są plany na dodanie operator overloading w TypeScript lub ECMAScript?
Na ten moment nie ma zatwierdzonych planów: zasadniczo przeciążenie operatorów jest sprzeczne z projektem JS, ponieważ może znacząco zmienić zachowanie standardowych obiektów i prowadzić do niestabilności kodu.
Programista tworzy klasę Matrix, gdzie implementuje valueOf/toString do podstawiania w wyrażeniach matematycznych. Przy dodawaniu do liczb lub łańcuchów otrzymuje nieprzewidywalne wyniki, niemożliwe jest ścisłe typowanie.
Plusy:
Minusy:
Klasa Vector implementuje metody add, multiply, equals z wyraźnym typowaniem parametrów wejściowych i wyjściowych. Klienci klasy wyraźnie używają odpowiednich metod, semantyka nie jest tracona, zapewnione jest ścisłe typowanie.
Plusy:
Minusy: