Typescriptのclassについて @yukilulu0229

## class

```class.ts

class Person {
  name: string;
  // 予約語 最初の処理すろとき
  constructor(initName: string) {
    this.name = initName;
  }
}

const yukilulu = new Person("yukilulu");
console.log(yukilulu)

```

## classにメソッドを追加する

```class.ts
class Person {
  name: string;
  constructor(initName: string) {
    this.name = initName;
  }  
  
  greeting(this: {name: string}) {
    console.log(`hello my name is ${this.name}`)
  }
}

const yukilulu = new Person("yukilulu");
yukilulu.greeting();

```
- アロー関数は使わない

```

greeting(this: {name: string}) {
    console.log(`hello my name is ${this.name}`)
}
```

- constructorのあとにメソッドを作る

```this: {name: string}```
- 第一引数にthisを使ってundefinedを回避する

## クラスを型として使う

```class.ts
class Person {
  name: string;
  constructor(initName: string) {
    this.name = initName;
  }

  // Personを直接型として入れ込む // 同時に型も作っているため
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}`)
  }
}

const yukilulu = new Person("yukilulu");
const another = {
  name: "0229",
  greeting: yukilulu.greeting
}

another.greeting();

```

```greeting(this:Person) {```
- 同時に型も作っている
- Personを直接型として入れ込むことで安全性を高める

```
const another = {
  name: "0229",
  greeting: yukilulu.greeting
}
```

```greeting: yukilulu.greeting```
ここもしっかり安全になる

## private修飾子

```class.ts
class Person {
  name: string;
  private age: number //classの外側からアクセスできないようにする
  constructor(initName: string, initAge: number) {
    this.name = initName;
    this.age = initAge
  }

  incrementAge() {
    this.age += 1;
  }
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`)
  }
}

const yukilulu = new Person("yukilulu", 29);
yukilulu.incrementAge();
// yukilulu.age = 30 これができないようなる
yukilulu.greeting();

```

```private age: number```
- classの外側からアクセスできないようにする

```// yukilulu.age = 30```
-  クラスの外のこれができないようなっている

```
incrementAge() {
    this.age += 1;
}
```
```
yukilulu.incrementAge();
```

なんだかの処理をした場合はクラス内で処理する

## 初期化の処理を省略

```class.ts
class Person {
  constructor(public name: string, private age: number) {}

  incrementAge() {
    this.age += 1;
  }
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`)
  }
}

const yukilulu = new Person("yukilulu", 29);
yukilulu.incrementAge();
yukilulu.greeting();

```

```
constructor(public name: string, private age: number) {}
```

()の中にprivate or publicを指定して書く

## readonly

```class.ts
class Person {
  readonly id: number = 32;
  constructor(public readonly name: string, private readonly age: number) {
    this.id = 4; // ここでは変更できる
  }

  // クラス内でも読み込みだけ
  // incrementAge() {
  //   this.age += 1;
  // }
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`)
  }
}

const yukilulu = new Person("yukilulu", 29,);
// yukilulu.incrementAge();
yukilulu.greeting();
// クラス外でも読み込みオンリー
// yukilulu.name = "0229"

```

```
constructor(public readonly name: string, private readonly age: number) {
```
ここで読み込み専用にする

```
readonly id: number = 32;
```
ここでも宣言できる

```
// yukilulu.name = "0229"
```
クラス外でも読み込みだけになる

```
 // incrementAge() {
  //   this.age += 1;
// }
```

クラス内でも読み込みだけ

```
constructor(public readonly name: string, private readonly age: number) {
    this.id = 4; // ここでは変更できる
}

```

コンストラクタ内では変更ができる

## 継承 extends

```class.ts

class Person {
  constructor(public readonly name: string, protected age: number) {}

  incrementAge() {
    this.age += 1;
  }
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`)
  }
}


class Teacher extends Person {
  constructor(name: string, age: number, public subject: string) {
    super(name, age);
  }
  greeting() {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old. I teach ${this.subject} `)
  }
}

const teacher = new Teacher("yukilulu", 29, "Math");
teacher.greeting();


```

```
class Teacher extends Person {
```

extendsでPersonを継承している

```
constructor(name: string, age: number, public subject: string) {
    super(name, age);
}
```

- コンストラクタにPesonにあるものは書く
- 追加したいものを書く

```
super(name, age);
```

superにPersonにあるものを書く

```
constructor(public readonly name: string, protected age: number) {}
```

- PersonのコンストラクタのageをprivateにしているとTeacherクラスで使えなくなってしまう
- そのため 継承したクラスで使えるprotectedにする必要がある
- 継承はできるprivateのような認識

## setterとgetter

```class.ts
class Teacher extends Person {
  constructor(name: string, age: number, private _subject: string) {
    super(name, age);
  }
  get subject(): string {
    if (!this._subject) {
      throw new Error("there is no subject")
    }
    return this._subject
  }

  set subject(value: string) {
    if (!value) {
      throw new Error("there is no subject")
    }
    this._subject = value
  }
  greeting() {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old. I teach ${this.subject} `)
  }
}

const teacher = new Teacher("yukilulu", 29, "Math");
teacher.greeting();
teacher.subject = "music"
console.log(teacher.subject)

```

```
constructor(name: string, age: number, private _subject: string) {
```

- コンストラクタの名前とsetterやgetterの名前を同一にできないので```_value```にするとよい

### getter

```
get subject(): string {
```
- getterは頭に ```get```をつける

- console.log(teacher.subject)のように使う

### setter

```
set subject(value: string) {
```
- setterは頭に```set```をつける
- 必ず引数を用意する

```
teacher.subject = "music"
```
- 変数で代入する

## static
インスタンスを作らすに取り扱う

```class.ts
class Person {
  static species = "Homo sapiens";
  static isAdult(age: number) {
    return age > 17;
  }
  constructor(public readonly name: string, protected age: number) {}

  incrementAge() {
    this.age += 1;
  }
  isAdlultAndSupiens(age: number) {
    return  Person.isAdult(age) && Person.species;
  }
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`)
  }
}

console.log(Person.species)
console.log(Person.isAdult(20));

```

```
static species = "Homo sapiens";
```

頭に```static```をつける

### インスタンスがないのにclass内でしようする場合

```
static isAdult(age: number) {
    return age > 17;
}
```

これを使いたい

```
isAdlultAndSupiens(age: number) {
    return  Person.isAdult(age) && Person.species;
}
```

頭に```Person```をつけてメソッドを呼び出す

## abstract
クラスを継承専用にする

```class.ts
abstract class Person {
  static species = "Homo sapiens";
  static isAdult(age: number) {
    return age > 17;
  }
  protected constructor(public readonly name: string, protected age: number) {}

  incrementAge() {
    this.age += 1;
  }
  isAdlultAndSupiens(age: number) {
    return  Person.isAdult(age) && Person.species;
  }
  greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`);
    this.explainJob()
  }

  abstract explainJob():void
}


class Teacher extends Person {
  explainJob() {
    console.log(`i am teacher. and teach ${this.subject}`)
  }

  constructor(name: string, age: number, private _subject: string) {
    super(name, age);
  }
  get subject(): string {
    if (!this._subject) {
      throw new Error("there is no subject")
    }
    return this._subject
  }

  set subject(value: string) {
    if (!value) {
      throw new Error("there is no subject")
    }
    this._subject = value
  }
}

// const person = new Person("yukilulu", 29); // 継承のためだけになったのでこれはできない
const teacher = new Teacher("yukilulu", 29, "Math");
teacher.greeting();

```

- ```// const person = new Person("yukilulu", 29); ```

- 継承のためだけになったのでインスタンス化のこれはできない


```
abstract class Person {
```
- 頭に```abstract```つける

```
greeting(this:Person) {
    console.log(`hello my name is ${this.name}. i am ${this.age} years old`);
    this.explainJob()
}

```

```
this.explainJob()
```

- ここで呼ばれている

```
abstract explainJob():void
```

- 継承用のメソッドを用意することができる

```
explainJob() {
    console.log(`i am teacher. and teach ${this.subject}`)
}

```

- teacherクラスに用意する

## シングルトンパターン
newできる回数を1度だけに制限する手法

```class.ts
class Teacher extends Person {
  private static instance: Teacher
  explainJob() {
    console.log(`i am teacher. and teach ${this.subject}`)
  }

  constructor(name: string, age: number, private _subject: string) {
    super(name, age);
  }
  get subject(): string {
    if (!this._subject) {
      throw new Error("there is no subject")
    }
    return this._subject
  }

  set subject(value: string) {
    if (!value) {
      throw new Error("there is no subject")
    }
    this._subject = value
  }

  static getInstance() {
    if (Teacher.instance) return  Teacher.instance;

    Teacher.instance = new Teacher("yukilulu", 29, "Math");
    return Teacher.instance;
  }
}
const teacher = Teacher.getInstance();
teacher.greeting();
```

```
private static instance: Teacher
```

- ```private static instance: Teacher```
を生成する

```
static getInstance() {
    if (Teacher.instance) return  Teacher.instance;

    Teacher.instance = new Teacher("yukilulu", 29, "Math");
    return Teacher.instance;
}
```

- ```static```でインスタンスを取得するメソッドを作る

```
if (Teacher.instance) return  Teacher.instance;
```
- これによって一回しか生成されなくする