TypeScriptで継承時にsuperとthisの挙動を正しく理解する方法
生徒
「先生、TypeScriptでクラスを継承するときにsuperとthisって出てくるんですけど、違いがよくわからないです。」
先生
「いい質問ですね。superは親クラス(スーパークラス)の機能を呼び出すときに使って、thisは今のクラス(自分自身のインスタンス)を指すときに使います。」
生徒
「なるほど…でも実際にどう違うのか、イメージが湧かないです。」
先生
「それでは、例を使ってsuperとthisの挙動を具体的に確認してみましょう!」
1. クラス継承におけるsuperとthisの役割
まず、継承(けいしょう)とは、あるクラスの機能を引き継いで新しいクラスを作る仕組みです。親クラスのことをスーパークラス、子クラスのことをサブクラスと呼びます。TypeScriptでクラスを継承するときには、extendsというキーワードを使います。
superは「親の機能を呼び出す合言葉」、thisは「自分自身を指す言葉」と覚えるとイメージしやすいです。
2. 基本的なサンプルコード
それでは、動物を例にしてsuperとthisを比較してみましょう。
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
speak(): void {
console.log(this.name + "が鳴いています");
}
}
class Dog extends Animal {
constructor(name: string) {
super(name); // 親クラスのconstructorを呼ぶ
}
speak(): void {
super.speak(); // 親クラスのメソッドを呼ぶ
console.log(this.name + "がワンワンと鳴きました");
}
}
const dog = new Dog("ポチ");
dog.speak();
ポチが鳴いています
ポチがワンワンと鳴きました
ここで、super.speak()は「親クラスのメソッドを実行」していて、そのあとthis.nameを使って「自分自身の名前」を参照しています。
3. constructor内でのsuperとthisの使い方
子クラスのconstructorでは、必ずsuper()を呼び出してからでないとthisを使うことはできません。これは、親クラスの初期化処理が終わらないと、自分自身を安全に扱えないためです。
class Cat extends Animal {
constructor(name: string) {
// superを呼ぶ前にthisを使うとエラーになる
super(name);
console.log("猫の名前は" + this.name + "です");
}
}
猫の名前はタマです
もしsuper()より前にthisを使おうとすると、TypeScriptが「親をまだ準備していません」と怒ってしまいます。
4. superとthisの違いをイメージで理解する
イメージとしては、superは「親に電話して助けてもらう」、thisは「自分で行動する」と考えるとわかりやすいです。例えば、犬クラスは自分で「ワンワン」と鳴けますが、その前に「親(動物)」としての鳴き方も知っているので、superを使って親の鳴き方を呼び出しています。
5. メソッドオーバーライドとsuperの活用
子クラスで親クラスと同じ名前のメソッドを定義することをオーバーライドと呼びます。このときにsuperを使えば、親の処理を引き継ぎつつ、追加で自分の処理を行うことができます。
class Bird extends Animal {
speak(): void {
super.speak();
console.log(this.name + "がピヨピヨ鳴いています");
}
}
const bird = new Bird("インコ");
bird.speak();
インコが鳴いています
インコがピヨピヨ鳴いています
このように、superをうまく使うとコードの再利用性が高まり、重複を避けることができます。
6. ポイント整理
TypeScriptでのsuperとthisは、それぞれ役割がはっきり分かれています。
super… 親クラスのconstructorやメソッドを呼び出す。this… 現在のインスタンス(自分自身)を指す。
特に初心者がつまずきやすいポイントは「constructorでは必ずsuperを呼んでからthisを使う」というルールです。これを理解するだけで、クラス継承がぐっと扱いやすくなります。
まとめ
superとthisの本質を丁寧に理解するための総まとめ
TypeScriptでクラスを継承するとき、superとthisの挙動はとても重要な要素になります。
この記事で学んできたように、クラス継承は親クラス(スーパークラス)から機能を受け継ぎつつ、新しい性質を加えて発展させるための強力な仕組みです。
その中で、superとthisの役割を正しく理解することは、柔軟で読みやすく、拡張性のあるコードを書くために欠かせません。
とくに、オブジェクト指向の基本である「親から継承し、子が上書きする」という流れを自然に表現するうえで、superは親の能力を呼び出す鍵となり、thisは自分自身の状態やプロパティを操作するための中心的な存在になります。
また、constructorの中ではsuper()より先にthisを触ることができないというルールを理解することも重要です。
これは、継承したサブクラスが使うべき基盤(親クラスの初期化)が整っていなければ、安全に動作させられないというTypeScriptの設計思想に基づいています。
こうした仕組みを把握しておくことで、エラーを避けるだけでなく、クラス同士の関連性をより深く理解できるようになります。
同時に、メソッドオーバーライドでsuper.speak()のように親の処理を生かしつつ、自分なりの動作を追加する構造は、実際の開発でも頻繁に登場するパターンです。
継承の基本的な形を繰り返し理解することで、より大規模なプログラムでも柔軟に対応できる力が身につきます。
サンプルコードでsuperとthisの役割をより深く理解する
以下のサンプルでは、親クラスと子クラスの関係、superとthisの振る舞いをさらに明確にするために、複数のクラスを組み合わせた例を紹介します。
実際の開発環境でも近い形で利用されるパターンなので、しっかり確認しておきましょう。
class Vehicle {
brand: string;
constructor(brand: string) {
this.brand = brand;
}
info(): void {
console.log(this.brand + "の車両情報を表示します");
}
}
class Car extends Vehicle {
type: string;
constructor(brand: string, type: string) {
super(brand); // 親クラスを初期化
this.type = type; // super呼び出し後なのでthisが使える
}
info(): void {
super.info(); // 親のinfoを利用
console.log(this.brand + "の" + this.type + "タイプの車です");
}
}
class SportsCar extends Car {
speed: number;
constructor(brand: string, type: string, speed: number) {
super(brand, type);
this.speed = speed;
}
info(): void {
super.info(); // Carのinfoを呼ぶ
console.log("最高速度は" + this.speed + "km/hです");
}
}
const ferrari = new SportsCar("フェラーリ", "スポーツカー", 320);
ferrari.info();
このコードでは、三段階の継承を行っています。
Vehicle → Car → SportsCarという流れの中で、superがどのように「ひとつ上のクラスの処理」を呼び出しているか確認できます。
とくにSportsCarのinfo()では、親クラスの処理を積み重ねるようにして、自分自身の機能を追加しています。
これは、TypeScriptでのクラス継承を自然に理解し、複雑な挙動でも整理して記述するための基盤となります。
superとthisを正しく使えば、関連性の深いオブジェクトでも整理された読みやすい構造を保ちながら拡張していくことができます。
superとthisを意識した設計で広がる応用範囲
superとthisの違いを理解することで、TypeScriptが提供するクラスベースのオブジェクト指向を深く扱うことができるようになります。
この理解は、Webアプリケーション、サーバーサイド処理、ゲーム開発、UIコンポーネントの構築など、さまざまな分野に応用できます。
子クラスが親クラスの機能を自然に活用できるようになることで、コードの重複を減らし、動作の一貫性を保ち、全体の保守性を高めることができます。
さらに、JavaScriptのクラスモデルをより深く理解するきっかけにもなり、TypeScript特有の型システムと組み合わせることで、より強力で堅牢なコードを書く基礎が身につきます。
生徒
「先生、今日の内容でsuperとthisの違いがだいぶわかってきた気がします!」
先生
「いいですね。とくにconstructorの中でsuper()より先にthisを触れない理由は大切ですよ。」
生徒
「確かに、親クラスが準備できていないと自分を扱えないっていうのは納得できました。」
先生
「その理解はとても重要です。継承したクラス同士のつながりを考えると自然ですよね。」
生徒
「superを使って親の処理を残しつつ、新しい動作を追加できるのも便利ですね!」
先生
「ええ、オーバーライドの本質はまさにそこにあります。次は自分でも継承を使ったクラス設計に挑戦してみましょう。」