問題の背景
多くの厳密に型付けされた言語(C++、C#、Python)は、クラスレベルでの演算子(例えば +、-、*、==)のオーバーロードを明示的に記述することを許可しています。しかし、TypeScriptはJavaScriptと同様に、歴史的およびアーキテクチャ的な理由から演算子のオーバーロードが言語レベルで欠如しています。
課題
複雑な型(例えば、複素数やベクトル)に対して算術やその他の操作のサポートを追加する必要があるとき、標準の演算子を変更することはできません。これは表現力を制限し、回避パターンを考案する必要があります。
解決策
TypeScriptでは、演算子のオーバーロードを特別に名付けられたメソッド(例えば add、equals、multiply)を通じて模倣します。クラスにこれらのメソッドを装備することで、C++のような簡潔さではないですが、型安全な動作を実現しています。
コード例:
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
重要な特徴:
TypeScriptで独自のクラスに対して "==" や "+" の演算子の動作をオーバーライドできますか?
いいえ、JavaScript(およびTypeScript)では、カスタムオブジェクトに対して標準演算子を直接オーバーロードすることはできません。演算子はObject、Numberなどのプリミティブに対して厳格に標準に従って適用されます。そのような「オーバーライド」を試みると、不正確または予期しない動作を引き起こしたり、単に機能しなくなります。
演算子に間接的に影響を与えるためにvalueOfやtoStringを使用できますか?
ある場合には、valueOfを使用することはできます(例えば、数への短い変換のために)が、あくまでオブジェクトのプリミティブ値にアクセスする演算子にだけです。
class Box { constructor(private v: number) {} valueOf() { return this.v; } } const a = new Box(10); console.log(a + 5); // 15 — 動作しますが、複雑なオブジェクトには直感的ではありません
しかし、複雑な構造や論理演算子の場合は、明示的なメソッドを使用するのが理にかなっています。
TypeScriptやECMAScriptに演算子オーバーロードを追加する計画はありますか?
現時点では、承認された計画はありません:原則として、演算子のオーバーロードはJSのデザインと矛盾しており、標準オブジェクトの動作を大きく変更し、コードの不安定性をもたらす可能性があります。
開発者がMatrixクラスを作成し、数学的表現に代入するためにvalueOf/toStringを実装します。数や文字列との加算で予測不可能な結果が得られ、厳密な型付けができません。
メリット:
デメリット:
Vectorクラスがadd、multiply、equalsのメソッドを実装し、入力および出力パラメータの明確な型付けを行います。クラスのクライアントは明確に対応するメソッドを使用し、意味は失われず、厳密な型付けが保証されています。
メリット:
デメリット: