4/14 TypeScript Class構文
オブジェクト思考プログラミング(OOP)とは
- OOPとは現実世界のものに見立ててプログラムする方法
- どのようにアプリケーションを作るかという方法の一つ
- 人間にとってわかりやすくロジックを分割する方法の一つ
どうやって作るの?となった時に、現実世界のものに見立ててみよう!という考え方です。
Classとは
- オブジェクトの設計図
- Classから作られたオブジェクトはインスタンスと呼ぶ
- 似たようなオブジェクトを複数作成するときに便利
Classの定義
person.ts
class Person { name: string; constructor(initName: string) { this.name = initName; } } const yano = new Person('yano'); console.log(yano);
実行結果
Person: { "name": "Yano" }
TypeScript playgroundで出力しています。
メソッド定義
やのさんに挨拶をしてもらうためのgreetingメソッドを定義しました。
class Person { name: string; constructor(initName: string) { this.name = initName; } greeting() { console.log(`おはようございます、${this.name}でございます`) } } const yano = new Person('Yano'); console.log(yano); yano.greeting();
出力結果
"おはようございます、Yanoでございます"
- このclass構文は省略した書き方ができますが、あえて基本から整理するために、省略していない書き方からアウトプットしています。
Classを型として使う方法
クラス宣言で重要な特徴として
クラスオブジェクトという値を作るものであると同時に、インスタンスの型を宣言するものであることです。
const yano = new Person('Yano'); // こうとも書けるということ const yano: Person = new Person('Yano');
このPerson型は、「string型のnameプロパティを持っていて、greetingメソッドを持つ」ということです。
であれば、new Personで作られたインスタンスでなくとも、この特徴を満たすものならば、Person型とすることができます。
const yunosuke: Person = { name: 'minegishi', greeting: () => console.log('おはす!') }
- Personのインスタンスと同じ特徴のyunosukeオブジェクトにはPersonの型を定義できている
※これはクラス宣言特有の挙動であり、クラス式では型は作られません。
クラス式の一例
const Person = class { neme: string = '' greeting() {} } // インスタンス化はできる const yano = new Person(); // error 型としては使えない const yunosuke: Person = new Person();
クラス宣言は、変数名と型名の両方の名前空間に、同時に名前を作成する構文であるということです。
private publicのアクセシビリティ修飾子
なぜ必要か
やのさんに挨拶に加えて、年齢も話してもらいました。
class Person { name: string; age: number; constructor(initName: string, initAge: number) { this.name = initName; this.age = initAge; } greeting(this: Person) { console.log(`おはようございます、${this.name}でございます。年齢は${this.age}です。`) } incrementAge() { this.age += 1; } } const yano: Person = new Person('Yano', 27); yano.greeting();
- ageプロパティを追加
- greetingメソッド内のテンプレートリテラルで年齢に関しての文言を追加
- 実行すると年齢に+1 をするincrementAgeメソッドを追加
実行結果
"おはようございます、Yanoでございます。年齢は27です。"
greetingメソッドより前に、incrementAgeメソッドを実行
class Person { name: string; age: number; constructor(initName: string, initAge: number) { this.name = initName; this.age = initAge; } greeting(this: Person) { console.log(`おはようございます、${this.name}でございます。年齢は${this.age}です。`) } incrementAge() { this.age += 1; } } const yano: Person = new Person('Yano', 27); yano.incrementAge(); yano.greeting();
実行結果
"おはようございます、Yanoでございます。年齢は28です。"
- 年齢に+1がされて、28歳になりました
ここで問題があります。
class Person { name: string; age: number; constructor(initName: string, initAge: number) { this.name = initName; this.age = initAge; } greeting(this: Person) { console.log(`おはようございます、${this.name}でございます。年齢は${this.age}です。`) } incrementAge() { this.age += 1; } } const yano: Person = new Person('Yano', 27); yano.incrementAge(); yano.age = 70; yano.greeting();
- yano.age = 70; に注目してください
実行結果
"おはようございます、Yanoでございます。年齢は70です。"
やのさんが70歳のおじいちゃんになってしまいました。
まだ若く有望な彼の年齢を、こうも簡単に変更できてしまっては困ります。
class Person { name: string; private age: number; constructor(initName: string, initAge: number) { this.name = initName; this.age = initAge; } greeting(this: Person) { console.log(`おはようございます、${this.name}でございます。年齢は${this.age}です。`) } incrementAge() { this.age += 1; } } const yano: Person = new Person('Yano', 27); yano.incrementAge(); yano.age = 70; // ageがコンパイルエラー yano.greeting();
- ageプロパティにprivate修飾子をつけています
- yano.ageのageでコンパイルエラーが発生して、70を代入できないようになりました
- class外からはアクセス不可能。class内では使用できます
- プロパティのみではなく、メソッドにも使用可能です
- console.log(yano.age)のように読み取りも不可です
※何もつけないとpublicになります
初期化の処理の省略記法
省略前
class Person { name: string; age: number; constructor(initName: string, initAge: number) { this.name = initName; this.age = initAge; }
省略後
class Person { constructor(public name: string, private age: number) {}
- constructorの引数に、アクセシビリティ修飾子をつけて、プロパティ名にするだけです
省略記法は、どのように省略されているかを理解しておくと良いと思います。
次回
静的プロパティ・静的メソッドから
参考
プロを目指す人のためのTypeScript入門
Udemy 超TypeScript入門 完全パック