HTML5テクニカルノート
TypeScript入門 03: クラスを継承して使う
- ID: FN1609004
 - Technique: HTML5 / JavaScript
 - Package: TypeScript 2.0.3
 
クラスを継承するとサブ(子)クラスは、スーパー(親)クラスのプロパティやメソッドを自らのものとして使えます。サブクラスを定めれば、スーパークラスの機能を拡張したり、使い途に応じたサブクラスをつくるなど、柔軟な開発ができるようになります。
01 サブクラスを定める
本稿は、「TypeScript入門 02: publicとprivateおよびstatic」で書いたコード002「クラスにプロパティやメソッドを加えたTypeScriptコード」に手を加えてゆきます。まず、クラス(Point)にprivate宣言したプロパティを、publicに変えましょう。キーワードprivateを消せば、デフォルトのpublicになります。けれど、publicはコンストラクタの引数に宣言することもできるのです。すると、つぎのようにプロパティへの代入も省いてしまえます。
class Point { // private x: number; // private y: number; constructor(public x: number, public y: number) { // this.x = x; // this.y = y; } }
クラスを継承するには、サブクラス(Vector)のclassの定めに、つぎのようにキーワードextendsでスーパークラス(Point)を与えます。そして、サブクラスのコンストラクタ(constructor())は、関数super()でスーパークラスのコンストラクタを呼びださなければなりません。
class Vector extends Point { constructor(x: number, y: number) { super(x, y); } }
これで、サブクラス(Vector)が定められました。まだ、サブクラス自らのプロパティもメソッドもありません。けれども、たとえばつぎのようにインスタンス(obj)をつくれば、スーパークラス(Point)のプロパティやメソッドが自らのものとして扱えます。ここまでのTypeScriptコードは、以下にまとめました(コード001)。
var obj: Vector = new Vector(1, Math.sqrt(3)); console.log(obj.getLength(), obj.getAngle() * Point.RAD_TO_DEG); // 1.9999999999999998 59.99999999999999
コード001■サブクラスを定める
class Point {
	static RAD_TO_DEG: number = 180 / Math.PI;
	constructor(public x: number, public y: number) {
	}
	getLength(): number {
		var square: number = this.x * this.x + this.y * this.y;
		return Math.sqrt(square);
	}
	getAngle(): number {
		return Math.atan2(this.y, this.x);
	}
	static polar(length: number, angle: number): Point {
		var x: number = length * Math.cos(angle);
		var y: number = length * Math.sin(angle);
		return new Point(x, y);
	}
}
class Vector extends Point {
	constructor(x: number, y: number) {
		super(x, y);
	}
}
02 サブクラスにインスタンスメソッドを加える
サブクラスへのメソッドの加え方は、通常のクラスと変わりません。つぎのようにふたつのメソッドを加えましょう。座標への定数(スカラー)倍(scale())と加算(add())です。後者の引数(point)の型には、スーパークラス(Point)を与えました。もちろん、サブクラス(Vector)のインスタンスも渡せます。
class Vector extends Point { scale(scale): void { this.x *= scale; this.y *= scale; } add(point: Point): void { this.x += point.x; this.y += point.y; } }
たとえば、つぎのコードでサブクラス(Vector)のインスタンス(obj)をつくると、サブクラスのインスタンスメソッド(scale()とadd())が呼び出せるとともに、スーパークラス(Point)のインスタンスメソッド(getLength()とgetAngle())も使えます。ここまでのサブクラスを定めたTypeScriptコードは以下にまとめました(コード002)。
var obj: Vector = new Vector(1, 0); obj.scale(2); // (2, 0) obj.add(new Vector(-1, Math.sqrt(3))); // (1, √3) console.log(obj.getLength(), obj.getAngle() * Point.RAD_TO_DEG); // 1.9999999999999998 59.99999999999999
コード002■サブクラスにインスタンスメソッドを加えた
class Point {
	static RAD_TO_DEG: number = 180 / Math.PI;
	constructor(public x: number, public y: number) {
	}
	getLength(): number {
		var square: number = this.x * this.x + this.y * this.y;
		return Math.sqrt(square);
	}
	getAngle(): number {
		return Math.atan2(this.y, this.x);
	}
	static polar(length: number, angle: number): Point {
		var x: number = length * Math.cos(angle);
		var y: number = length * Math.sin(angle);
		return new Point(x, y);
	}
}
class Vector extends Point {
	constructor(x: number, y: number) {
		super(x, y);
	}
	scale(scale): void {
		this.x *= scale;
		this.y *= scale;
	}
	add(point: Point): void {
		this.x += point.x;
		this.y += point.y;
	}
}
03 サブクラスに静的メソッドを加える
サブクラス(Vector)に静的メソッドを加えることもできます。やり方は、普通のクラスと同じです。原点(0, 0)からの距離と角度を引数に渡して、インスタンスが返されるメソッドにします。スーパークラス(Point)には、すでにこのような静的メソッド(polar())が備わっています。けれど、返されるのはスーパークラスのインスタンスですから、サブクラスのメソッドが使えません。そこで、同じ名前のつぎのような静的メソッド(polar())をサブクラスに加えました。座標計算は同じなので、スーパークラスの静的メソッドでつくったオブジェクトから取り出した座標により、サブクラスの新たなインスタンスをつくって返しています。
class Vector extends Point { static polar(length: number, angle: number): Vector { var point: Point = Point.polar(length, angle); return new Vector(point.x, point.y); } }
これで、つぎのようにサブクラス(Vector)の静的メソッド(polar())でインスタンス(obj)がつくられ、サブクラスとスーパークラス(Point)どちらのメソッドも呼び出せます。TypeScriptコードは以下にまとめました(コード003)。なお、以下にサンプル001としてjsdo.itに書いたコードを掲げてあります。
var obj: Vector = Vector.polar(0.5, Math.PI / 3); obj.scale(2); console.log(obj.getLength(), obj.getAngle() * Point.RAD_TO_DEG); // 1 59.99999999999999
コード003■サブクラスに静的メソッドを加えた
class Point {
	static RAD_TO_DEG: number = 180 / Math.PI;
	constructor(public x: number, public y: number) {
	}
	getLength(): number {
		var square: number = this.x * this.x + this.y * this.y;
		return Math.sqrt(square);
	}
	getAngle(): number {
		return Math.atan2(this.y, this.x);
	}
	static polar(length: number, angle: number): Point {
		var x: number = length * Math.cos(angle);
		var y: number = length * Math.sin(angle);
		return new Point(x, y);
	}
}
class Vector extends Point {
	constructor(x: number, y: number) {
		super(x, y);
	}
	scale(scale): void {
		this.x *= scale;
		this.y *= scale;
	}
	add(point: Point): void {
		this.x += point.x;
		this.y += point.y;
	}
	static polar(length: number, angle: number): Vector {
		var point: Point = Point.polar(length, angle);
		return new Vector(point.x, point.y);
	}
}
サンプル001■TypeScript: Definig a subclass and adding methods to it
- TypeScript: とにかくJavaScriptファイルをビルドしてみる
 - TypeScript入門 01: Visual Studio CodeでTypeScriptのコードを書く
 - TypeScript入門 02: publicとprivateおよびstatic
 - TypeScript入門 04: オブジェクト型リテラルとインタフェースを使う
 - TypeScript入門 05: get/setアクセサをを使う
 - TypeScript入門 06: メソッド引数のデフォルト値と省略および定数を定める
 - TypeScript入門 07: ブロックスコープに変数を宣言する ー let
 - TypeScript入門 08: 型の互換性
 - TypeScript入門 09: アロー関数式
 - TypeScript入門 10: モジュール ー exportとimport
 - TypeScript入門 11: 名前空間 ー namespace
 - TypeScript入門 12: デコレータ(Decorator)を使う
 
作成者: 野中文雄
更新日: 2016年9月23日 TypeScriptのバージョンを2.0.3に更新。
作成日: 2016年9月12日
Copyright © 2001-2017 Fumio Nonaka. All rights reserved.