インターフェース、型パラメーター、型ガードも活用!TypeScriptで基底クラスのメンバーにアクセスする

2024-04-02

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 を使って、基底クラス Animalname プロパティにアクセスしています。

  • メソッドへのアクセス:
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 演算子を使用して animalDog クラスのインスタンスかどうかをチェックし、as キーワードを使用して Dog 型にキャストします。

基底クラスのメンバーにアクセスするには、いくつかの方法があります。どの方法を使うべきかは、状況によって異なります。

  • 直接アクセス: 基底クラスの public メンバーにアクセスする

typescript


【TypeScript】クラスをパラメータとして渡す際の「is not newable」エラーを徹底解説

このエラーのよくある原因と解決策は以下の通りです。原因 1: 誤った型の使用渡している型が実際にクラスを表していない可能性があります。例えば、インターフェースや型エイリアスを誤って渡している場合があります。渡している型がクラスであることを確認してください。...


TypeScript初心者でも安心!nullとundefinedのチェックをマスターしよう

== nullを使用するこれは最も簡単な方法で、==演算子を使用して変数をnullと比較します。この方法は、nullとundefinedの両方をチェックするのに便利ですが、厳密な比較ではないことに注意が必要です。=== nullと=== undefinedを使用する...


コードをよりスマートに:TypeScript、JSLint、TSLintにおける空ブロックの取り扱い

TypeScript、JSLint、TSLint などの静的解析ツールは、コードの品質と一貫性を向上させるために役立ちます。これらのツールは、潜在的な問題を特定し、コードをより読みやすく、保守しやすくすることができます。しかし、これらのツールは、空ブロックなどの無意味なコードがあると警告を出すことがあります。空ブロックとは、{} で囲まれたコードブロックであり、何も記述されていないものです。...


【初心者向け】TypeScriptの「isNaN」関数:サンプルコードで理解を深める

TypeScriptにおける isNaN 関数は、数値型以外の値を受け付けないという制約があります。これは、isNaN 関数が数値型であることを前提に内部処理を行うためです。この制約は、予期しない動作や型エラーを引き起こす可能性があるため、注意が必要です。...


Angular 5 でチェックボックスを自在に操る!HTMLテンプレートとTypeScriptでブール値を制御する方法

ngModel ディレクティブは、フォーム要素とコンポーネントのプロパティを双方向にバインドするために使用されます。チェックボックスの場合、ngModel を使って、チェックボックスの状態をブール値のプロパティにバインドすることができます。...


SQL SQL SQL SQL Amazon で見る



上級TypeScript開発者向け: getとsetの深い理解

TypeScriptでは、getとsetアクセサを使用して、プロパティの読み書きを制御できます。これは、データの検証や、その他の処理をプロパティのアクセスに関連付ける場合に役立ちます。getアクセサは、プロパティの値を取得するために呼び出されます。以下に例を示します。