インターフェース、型パラメーター、型ガードも活用!TypeScriptで基底クラスのメンバーにアクセスする
TypeScriptにおける基底クラスのメンバーへのアクセス
メンバーの種類
基底クラスのメンバーには、以下の2種類があります。
- プロパティ: データを表す変数のようなものです。
- メソッド: 処理を実行する関数のようなものです。
アクセス場所
基底クラスのメンバーにアクセスする場所は、以下の2つが考えられます。
- 派生クラス: 基底クラスを継承したクラスです。
- 基底クラス自身: 基底クラスのインスタンスまたは静的メンバーからアクセスする場合です。
アクセス方法
super
キーワードは、派生クラスから基底クラスのメンバーにアクセスするために使用します。
- プロパティへのアクセス:
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log(` ${this.name} barks!`);
}
}
const dog = new Dog('Rex');
dog.bark(); // Rex barks!
上記の例では、Dog
クラスの bark()
メソッド内で super.name
を使って、基底クラス Animal
の name
プロパティにアクセスしています。
- メソッドへのアクセス:
class Animal {
protected move() {
console.log('♀♂');
}
}
class Dog extends Animal {
run() {
super.move();
console.log('');
}
}
const dog = new Dog();
dog.run(); // ♀♂
直接アクセス
基底クラスのメンバーが public
修飾子付きの場合は、派生クラスから直接アクセスできます。
class Animal {
public name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log(` ${this.name} barks!`);
}
}
const dog = new Dog('Rex');
console.log(dog.name); // Rex
上記の例では、Dog
クラスから Animal
クラスの public
プロパティ name
に直接アクセスしています。
protected メンバーへのアクセス
class Animal {
protected move() {
console.log('♀♂');
}
}
class Dog extends Animal {
run() {
this.move(); // OK
}
}
const dog = new Dog();
// dog.move(); // エラー: 'move' は 'Dog' からアクセスできません
TypeScriptで基底クラスのメンバーにアクセスするには、以下の方法があります。
super
キーワードを使う- 直接アクセスする (public メンバーのみ)
protected
メンバーの場合は、派生クラスからthis
キーワードを使ってアクセスする
どの方法を使うべきかは、アクセスしたいメンバーの種類と、アクセスする場所によって異なります。
super キーワード
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
protected move() {
console.log('♀♂');
}
}
class Dog extends Animal {
bark() {
console.log(` ${this.name} barks!`);
}
run() {
super.move();
console.log('');
}
}
const dog = new Dog('Rex');
dog.bark(); // Rex barks!
dog.run(); // ♀♂
直接アクセス
class Animal {
public name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
bark() {
console.log(` ${this.name} barks!`);
}
}
const dog = new Dog('Rex');
console.log(dog.name); // Rex
protected メンバーへのアクセス
class Animal {
protected move() {
console.log('♀♂');
}
}
class Dog extends Animal {
run() {
this.move(); // OK
}
}
const dog = new Dog();
// dog.move(); // エラー: 'move' は 'Dog' からアクセスできません
- 上記のサンプルコードは、あくまでも基本的な例です。
- より複雑なケースでは、他の方法も必要になる場合があります。
基底クラスのメンバーにアクセスするその他の方法
インターフェースを使用して、基底クラスと派生クラスの間で共通のメンバーを定義することができます。
interface Animal {
name: string;
move(): void;
}
class Animal implements Animal {
name: string;
constructor(name: string) {
this.name = name;
}
move(): void {
console.log('♀♂');
}
}
class Dog extends Animal {
bark(): void {
console.log(` ${this.name} barks!`);
}
}
const dog = new Dog('Rex');
dog.name; // 'Rex'
dog.move(); // ♀♂
上記の例では、Animal
インターフェースを定義し、name
プロパティと move()
メソッドを定義しています。Animal
クラスと Dog
クラスはどちらも Animal
インターフェースを実装しているので、これらのメンバーにアクセスすることができます。
型パラメーターを使用して、基底クラスの型を派生クラスに渡すことができます。
class Animal<T> {
protected name: T;
constructor(name: T) {
this.name = name;
}
protected move(): void {
console.log('♀♂');
}
}
class Dog extends Animal<string> {
bark(): void {
console.log(` ${this.name} barks!`);
}
}
const dog = new Dog('Rex');
// dog.name; // エラー: 'name' は 'Dog' からアクセスできません
上記の例では、Animal
クラスは型パラメーター T
を受け取り、name
プロパティの型として使用します。Dog
クラスは string
型を Animal
クラスの型パラメーターとして渡しているので、name
プロパティは string
型になります。
型ガードを使用して、基底クラスのインスタンスの種類をチェックし、それに応じてメンバーにアクセスすることができます。
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
protected move(): void {
console.log('♀♂');
}
}
class Dog extends Animal {
bark(): void {
console.log(` ${this.name} barks!`);
}
}
const animal: Animal = new Dog('Rex');
if (animal instanceof Dog) {
const dog = animal as Dog;
dog.bark(); // Rex barks!
}
上記の例では、animal
変数は Animal
型ですが、Dog
クラスのインスタンスを格納しています。instanceof
演算子を使用して animal
が Dog
クラスのインスタンスかどうかをチェックし、as
キーワードを使用して Dog
型にキャストします。
基底クラスのメンバーにアクセスするには、いくつかの方法があります。どの方法を使うべきかは、状況によって異なります。
- 直接アクセス: 基底クラスの
public
メンバーにアクセスする
typescript