時給単価UP【3大特典付き】
コーディングテクニック集100選⋙

【解説】TypeScriptで使うクラスの型【まとめてみた】

記事内に広告を含みます

TypeScriptで使うクラスの書き方を自分用のメモとしてまとめてみました!

参考になれば幸いです。

ちなみにクラスやTypeScriptの基本的な型定義は下記をどうぞ↓

【解説】JavaScriptのクラスの使い方【フィールド/static/extends/super】 【解説】TypeScriptの型定義をまとめてみた【初心者向け】

【解説】TypeScriptで使うクラスの型【まとめてみた】

TypeScriptでのクラスの型について、下記の順に解説していきます。

・クラスの基本的な使い方

・クラスのthisの注意点

・クラスを型に使う

・クラスに型を指定する

・「public修飾子」「private修飾子」

・クラスの初期化処理を省略する

・「readonly修飾子」

・「protected修飾子」

・Abstractクラス(抽象クラス)

・シングルトンパターン

1つずつ見ていきましょう。

基本的なクラスの使い方

まず基本的なクラスを使った例となるコードがこちら↓

class Fruit {
  name: string;
  constructor(fruitName: string) {
    this.name = fruitName;
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}です。`);
  }
}

const orange = new Fruit('みかん');
orange.nameFunc(); // この果物の名前はみかんです。

Fruitというクラスを作り、果物の名前をコンソールログで出力するメソッドを入れました。

これでインスタンス化して引数に果物名を入れ、メソッドを呼び出せば名前が出力できます。

このコードを基本として、これからクラスで使える型を解説していきます。

クラスのthisの注意点

クラスでthisを使うときの注意点があります。

それが新たに作ったオブジェクトの中に、クラスのメソッドを入れると「this ~~」が「undefined」になることです。

class Fruit {
  name: string;
  constructor(fruitName: string) {
    this.name = fruitName;
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}です。`);
  }
}

const orange = new Fruit('みかん');

const otherFruit = {
  otherFruitName :orange.nameFunc,
}

otherFruit.otherFruitName(); // この果物の名前はundefinedです。

thisは実行部分に影響されるので、上記だと「otherFruit」というオブジェクト内にnameがないので未定義となります。

未定義となるだけで、TypeScriptがエラーで表示はしてくれません。。

ジト
ジト

TypeScriptだとそのthisがなに使ってるかまで、見てくれない。。

そこでクラスのメソッドの第一引数に、偽の「this」という名前をつけます。

nameFunc(this: {name: string}) {
 ~~
}
class Fruit {
  name: string;
  constructor(fruitName: string) {
    this.name = fruitName;
  }
  nameFunc(this: {name: string}) {
    console.log(`この果物の名前は${this.name}です。`);
  }
}

const orange = new Fruit('みかん');

const otherFruit = {
  name: '新しいみかん',
  otherFruitName :orange.nameFunc,
}

otherFruit.otherFruitName(); // この果物の名前はみかんです。

これでnameプロパティがないとちゃんとエラーを表示してくれます↓

クラスを型に使う

実はTypeScriptではクラスを作るときに、同時にそのクラスの型も同じ名前で作成してくれます。

そのためthisに対して、そのクラスの型名を記述してもうまく動きます。

class Fruit {
  name: string;
  constructor(fruitName: string) {
    this.name = fruitName;
  }
  nameFunc(this: Fruit) {
    console.log(`この果物の名前は${this.name}です。`);
  }
}

const orange = new Fruit('みかん');

const otherFruit = {
  name: '新しいみかん', // ないとエラーが出る
  nameFunc :orange.nameFunc, // ないとエラーが出る
}

otherFruit.nameFunc(); 

これで「otherFruit」のなかに、nameプロパティ・nameFuncメソッドがないとエラーがでるようになります。

クラスに型を指定する

TypeScriptではクラスに型を指定することが可能です。

「interface」もしくは「typeエイリアス」で指定した型を、「implements」を使ってクラスに指定することができます。

interface FruitInfo {
  name: string;
  nameFunc(): void;
} // ちなみにtypeエイリアスでもOK

class Fruit implements FruitInfo {
  name: string;
  constructor(fruitName: string) {
    this.name = fruitName;
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}です。`);
  }
}

const orange = new Fruit('みかん');
orange.nameFunc(); // この果物の名前はみかんです。

これで「Fruit」クラスには、「FruitInfo」で定義したプロパティやメソッドが必要になります。

ただしそれよりも多いプロパティやメソッドを、「Fruit」クラスで定義するぶんにはエラーがでません。

【解説】TypeScriptのインターフェースの使い方【interface】

「public修飾子」「private修飾子」

プロパティやメソッドの前に下記修飾子をつけることで、アクセスできるかを指定できます。

  • 「public修飾子」⇒クラスの外でも中でもアクセス可能。デフォルト。
  • 「private修飾子」⇒クラスの中でのみアクセス可能。
class Fruit {
  public name: string;
  private num: number;
  constructor(fruitName: string, fruitNum: number) {
    this.name = fruitName;
    this.num = fruitNum;
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
}

const orange = new Fruit('みかん', 3);
orange.name = 'オレンジ' // これはOK
orange.num = 5; // これはエラーがでる

ちなみに「private修飾子」はインスタンス化するときには使用可能です。
(コンストラクタ内で初期化するので)

クラスの初期化処理を省略する

constructorのパラメータの先頭に「pbulic」や「private」の修飾子をつけることで、初期化処理を省略することができます。

class Fruit {
  constructor(public name: string, private num: number) {
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
}

const orange = new Fruit('みかん', 3);
orange.nameFunc(); // この果物の名前はみかんで数は3です。

「readonly修飾子」

「readonly修飾子」をつけることで、読み取り専用にすることができます。

  • 読み取り専用
  • 書き込みはできない
  • フィールドでも使用可能
  • constructor内の初期化では書き込み可能
  • 「public修飾子」「private修飾子」も付ける場合は、その後ろに記述
class Fruit {
  constructor(public readonly name: string, private readonly num: number) {
    this.name = 'りんご';
    this.num = 5;
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
}

const orange = new Fruit('みかん', 3);
orange.name =  'ぶどう'; // これはエラーが出ます。
orange.nameFunc(); // この果物の名前はみかんで数は3です。

「protected修飾子」

クラスには「protected修飾子」という、継承先まではアクセス可能な「private」を少しゆるくしたものが使えます。

  • 「private修飾子」⇒クラスの継承先もアクセスできない
  • 「protected修飾子」⇒継承先まではアクセス可能。外からはアクセス不可能。

例として「private修飾子」を用いたクラスを継承するコードを書いてみました。

class Fruit {
  constructor(public name: string, private num: number) {
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
}

const orange = new Fruit('みかん', 3);

class Food extends Fruit {
  constructor(name: string, num: number, public volume: number ) {
    super(name, num);
  }
  nameFunc() {
    console.log(`この食べ物の名前は${this.name}で数は${this.num}です。量は${this.volume}です。`);
  }
}

const drink = new Food('りんご', 5, 10);

このままだと「Fruit」クラスのnumがprivateのため、「Food」クラスにてnumにアクセスすることができません。

エラーがでてしまいます↓

そこで使えるのが「protected修飾子」です。

継承先まではアクセスすることができるため、下記だとエラーがでません。

class Fruit {
  constructor(public name: string, protected num: number) {
  }
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
}

const orange = new Fruit('みかん', 3);

class Food extends Fruit {
  constructor(name: string, num: number, public volume: number ) {
    super(name, num);
  }
  nameFunc() {
    console.log(`この食べ物の名前は${this.name}で数は${this.num}です。量は${this.volume}です。`);
  }
}

const apple = new Food('りんご', 5, 10);

Abstractクラス(抽象クラス)

Abstractとは「設計ルールを持つ、インスタンス化できない親クラス」です。

ようは継承のために使われるクラスのこと。

継承先で使われるであろう処理を親クラスで書いておいて、子で使う感じです。

ジト
ジト

子クラスに「これだけは必ず実装してね」と約束してるクラスとも言えるね

例として書いたコードがこちら
親クラス「Fruit」で記述したメソッドを、「Food」にて実行しております。

abstract class Fruit {
  constructor(public name: string, protected num: number) {}
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
    this.getDescription();
  }
  abstract getDescription(): void;
}

class Food extends Fruit {
  constructor(name: string, num: number, private extra: number) {
    super(name, num);
  }
  getDescription() {
    console.log(`${this.name}は食べ物です。数は${this.num}で、追加で${this.extra}個あります。`);
  }
}

const apple = new Food('りんご', 5, 10);
apple.nameFunc();
// この果物の名前はりんごで数は5です。
// りんごは食べ物です。数は5で、追加で10個あります。
  • 1行目:「abstract」を使うには、クラスの先頭に「abstract」をつける
  • 5行目:子で使う処理を、親で記述
  • 7行目:継承先で必ず使う処理に対して、先頭に「abstract」を記述
  • 7行目:暗黙的なanyではいけない(今回は: voidを記述)
  • 14 ~ 16行目:親で書いていた処理名を、子で実装
  • この親クラスはインスタンス化することはできない

シングルトンパターン

constructorには「private修飾子」をつけることが可能です。

class Fruit {
  private constructor(public name: string, protected num: number) {}
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
}

const orange = new Fruit(); // エラーがでます。

これをするとインスタンス化することができません。

これはシングルトンパターンという「クラスのインスタンスがただ1つしか存在しない」ものを用いるときに使えるものです。

ジト
ジト

いわゆるデザインパターンだね

ただインスタンス化できないとなると、どう使うのでしょうか。

staticを使えばクラスの中でインスタンス化が可能です↓

class Fruit {
  private constructor(public name: string, protected num: number) {}
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
  static getfruitInstance() {
    const fruitInstance = new Fruit('みかん', 5);
    return fruitInstance
  }
}

これでインスタンス化ができました。

ただこのままでは「fruitInstance」「fruitInstance02」「fruitInstance03」みたいに変数をたくさん作れば作るほど、インスタンス化できちゃいますよね。。

ではどうするのか。。

そこで「唯一のインスタンスを保持する静的プロパティ」を作ります。

class Fruit {
  private static instance: Fruit;

  private constructor(public name: string, protected num: number) {}
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
  static getfruitInstance() {
    const fruitInstance = new Fruit('みかん', 5);
    return fruitInstance
  }
}

こうすると「getfruitInstanceメソッド」から、staticなinstanceにアクセスすることができます。

あとはインスタンス化がされてるかどうかを、if文で判定すれば対応可能です。

インスタンス化されてればインスタンスを返して、されていなければインスタンス化するということですね。

class Fruit {
  private static instance: Fruit;

  private constructor(public name: string, protected num: number) {}
  nameFunc() {
    console.log(`この果物の名前は${this.name}で数は${this.num}です。`);
  }
  static getfruitInstance() {
    if (!Fruit.instance) {
      Fruit.instance = new Fruit('みかん', 5);
    }
    return Fruit.instance
  }
}

これでインスタンスが1つしか作られないクラスができました!

【解説】TypeScriptで使うクラスの型【まとめてみた】:まとめ

  • TypeScriptのクラスでthisを使うときは注意
  • TypeScriptではクラス作成時にそのクラスの型も作る
  • 「implements」を使えばクラスに型を指定できる
  • 「public修飾子」⇒クラスの外でも中でもアクセス可能
  • 「private修飾子」⇒クラスの中でのみアクセス可能
  • 「readonly修飾子」⇒読み取り専用
  • 「protected修飾子」⇒クラスの継承先はアクセス可能。外は不可
  • 「Abstract」⇒継承先で使われる処理を親クラスで書き、子で使う
  • 「シングルトンパターン」⇒クラスのインスタンスがただ1つしか存在しないデザインパターン
ジト
ジト

TypeScriptでクラスを使う時はためしてみてね!

ちなみにクラスやTypeScriptの基本的な型定義は下記をどうぞ↓

【解説】JavaScriptのクラスの使い方【フィールド/static/extends/super】 【解説】TypeScriptの型定義をまとめてみた【初心者向け】

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA