TypeScriptメモ 〜オブジェクト編〜

###ファクトリ関数

値を生成するための関数。
同じ形式のオブジェクトを何回も作れる。

```typescript
function Person(n:string, a: number) {
  return {
    name: n,
    age: a,
    print: function(){
      console.log(this.name)
      console.log(this.age)
    }
  }
}
```

###オブジェクトの分割代入

```typescript
type person = { name: { first: string, second: string }, age: number }

const foo:person = { name: { first: 'foo', second: 'bar' }, age: 20 }
const { name: { first, second }, age } = foo
```

###クラス

```typescript
class Person {
  name: string = 'default'
  email?: string
  age?: number
  print(): void {
    // 何らかの処理
  }
}
```

### インスタンスのクラスを調べる

```typescript
インスタンス instanceof クラス // boolean
```

###インスタンスのクラス名を得る

```typescript
インスタンス.constructor.name
```

###継承

```typescript
class Person {...}

class Student extends Person {}
```

###アクセス修飾子

プロパティのアクセスを制限する時に

|修飾子|説明|
|:--|:--|
|public|外部から自由にアクセス可|
|protected|クラスと継承クラスからアクセス可|
|private|クラス内のみアクセス可|


###setterとgetter

「直接アクセスされては困るが、完全にアクセスできないのも困る」という時に。
**private+setter/getter**という使い方が一般的

```typescript
class Person {
  private age: number
  get getAge():number {
    return this.age
  }
  set setAge(n:number) {
    this.age = n
  }
}
```

### インターフェイス

クラスの構造の定義をするためのもの。
**インターフェイスで定義したプロパティをクラスは用意しなければならない。**

```typescript
enum School {
  junior = 'junior',
  juniorHigh = 'juniorHigh',
  high = 'high'
}

interface Human {
  name: string
  print(): void
}

class Person implements Human {
  name: string = 'no-name'
  mail: string
  age: number

  constructor(name: string, mail: string = 'no-mail', age: number = -1) {
    this.name = name
    this.mail = mail
    this.age = age
  }

  print():void {
    console.log(this.name)
    console.log(this.mail)
    console.log(this.age)
  }
}

class Student implements Human {
  name: string = 'no-name'
  school: School
  grade?: number

  constructor(name: string, school?: School, grade?: number) {
    this.name = name
    this.school = school
    this.grade = grade
  }

  print():void {
    console.log(this.name)
    console.log(this.school)
    console.log(this.grade)
  }
}
```

利点としては**継承関係にないインスタンスをインターフェイスによってまとめられる**

```typescript
const taro: Person = new Person('taro', 'taro@yamada', 20)
const hanako: Student = new Student('hanako', School.high, 2)
const sachiko: Person = new Person('sachiko')
const jiro: Student = new Student('jiro', School.high)

const data:Human[] = [taro, hanako, sachiko, jiro]
```

###インターフェイスの継承

```typescript
interface People extends Human {...}
```

###抽象クラス

interface同様クラスにメソッドを用意するために使用。ただし、抽象クラスに用意される抽象メソッドは実装がないため継承しても使えない。

```typescript
abstract class Human {
  abstract print(): void
}

class Person extends Human {...}

class Student extends Human {...}
```

###抽象クラスとインターフェイスの違い

+ **他にクラスを継承するか？**

他のクラスを継承するのであれば、抽象クラスは使用できない

+ プロパティを義務付ける必要があるか？

抽象クラスは基本的に「メソッド」を定義するもの。
**実装クラスに必ずプロパティをもたせたいなら、インターフェイスを使用**

+ protectedか、publicか？

インターフェイスはpublicなメソッドを定義。protectedメソッドは使えない。

###静的メンバー

インスタンスを作る必要がないクラス。クラスのプロパティやメソッドを**静的メンバー**としてまとめる。

```typescript
class StaticHuman {
  static fullname:string // nameは予約語なので使用できない！
  static age:number

  static set(nm:string, age:number):void {
    this.fullname = nm
    this.age = age
  }

  static print():void {
    console.log(this.fullname)
    console.log(this.age)
  }
}

StaticHuman.set('taro', 40)
StaticHuman.print()
StaticHuman.set('foo', 20)
StaticHuman.print()
```

###パラメータプロパティ

readonlyを使用。読み取り専用のプロパティを使用できる

```typescript
class Human {
  constructor(readonly name:string, readonly age:number) {}
}
```

###総称型の利用

```typescript
class Data<T> {
  data?:T[]

  constructor(...item:T[]) {
    this.data = item
  }

  print():void {
    if (this.data) {
      for(let item of this.data) {
        console.log(item)
      }
    } else {
      console.log('no data...')
    }
  }
}

const data1 = new Data<string>('one', 'two', 'three')
const data2 = new Data<number>(1, 2, 3)
```

###ユーティリティ型

ここでは、Requiredというユーティリティ型を使用している。これにより、Personのhumanプロパティではname, mail, ageのすべての値が必須になる。

```typescript
type Human = {
  name:string
  mail?:string
  age?:number
}

class Person {
  human:Required<Human>

  constructor(nm:string, ml:string, ag:number) {
    this.human = { name:nm, mail:ml, age:ag }
  }

  print():void {
    console.log(this.human)
  }
}
```