TypeScriptの関数・クラスに関する文法と型

# はじめに
私がまとめたTypeScriptに関する記事一覧になります。もし興味がありましたらご覧になってください。
* [TypeScriptの基本的な文法・型](https://qiita.com/Hirohana/items/d93820bd6bc514aec116 "TypeScriptにおける基本的な文法・型")
* [TypeScriptの関数・クラスに関する文法と型](https://qiita.com/Hirohana/items/553353c82c8107a3358b "TypeScriptの関数・クラスに関する高度な文法と型")
* [TypeScriptの高度な型(Utility Types、Conditional Types)](https://qiita.com/Hirohana/items/9c85e65c6e09b9f8b5c8 "TypeScriptの高度な型(Utility Types、Conditional Types")

今回は、**TypeScriptの関数・クラスに関する文法と型**についての記事になります。

## 関数・クラスで共通な文法と型

### 型引数
* type文やinterface宣言、クラスで型を作成する時に宣言
* 型引数はその宣言の中(type文だと=の右側)でだけ有効な型名として扱われる
* 型引数が複数ある場合は、型引数を,で区切って<>の中に並べる。
* 型引数を持つ型は`ジェネリック型`とも呼ばれる
```typescript
// 型引数T, Uを使ってプロパティの型を定義
type User<T, U> = {
  name: T;
  age: U;
};

const user: User<string, number> = {
  name: 'Hiro',
  age: 30,
};
```

## 関数における文法と型

### 関数の型定義
* 関数宣言に対しては、引数と戻りに対して型を定義する
* 関数式とアロー関数式に対しては、関数自体にも型定義が可能

```typescript: 
// 関数宣言
function add(val1: number, val2: number) {
    return val1 + val2;
}

// 関数式
const add = function(val1: number, val2: number) {
    return val1 + val2;
}

// アロー関数式
const add: (val1: number, val2: number) => number = (val1, val2) => val1 + val2;
```

### 呼び出しシグネチャ
* TypeScriptにおける関数の型を定義するための構文
* 関数を引数として返す場合や、関数を別の関数から返す際に使用する
* type alias(型エイリアス)を利用して、独立したシグネチャとして定義することも可能
* 型エイリアスは、省略記法と完全記法がある

```typescript
// 呼び出しシグネチャ
(message: string, userId: string) => void

// type aliasを使った呼び出しシグネチャ(省略記法)
type Log = (message: string, userId: string) => void;

// type aliasを使った完全な呼び出しシグネチャ(完全記法)
type Log = {
    (message: string, userId: string): void
}
```

### ジェネリクス
* 関数やクラスの再利用性と柔軟性を向上させるための重要な機能
* ジェネリクスを使用すると、関数やクラスの処理内容は同じままで、引数や戻り値の型が異なる場合に、関数定義やクラス定義を複数作成する必要がなくなる
* ジェネリクスを使うことで、型をパラメータとして扱い、動的に異なる型を処理することが可能
```typescript
// 関数の処理内容が全く同じで、引数と戻り値の型が違う
const repeatStr = (value: string, times: number): string[] => {
  return new Array(times).fill(value);
};
const repeatNum = (value: number, times: number): number[] => {
  return new Array(times).fill(value);
};

// 型引数を使った以下の関数を定義すれば、関数を2つ定義しなくても同じ処理が行える
const repeat = <T>(value: T, times: number): T[] => {
  return new Array(times).fill(value);
};
const strArray = repeat<string>('hello', 3);
const strNum = repeat<number>(10, 3);
```

## クラスにおける文法と型

### クラスの型定義
* プロパティやコンストラクタ引数、メソッドの引数や戻り値に対して型を定義
```typescript
// クラスは型引数も使用可能
class User<T> {
  name: T;
  age: number;

  constructor(name: T, age: number) {
    this.name = name;
    this.age = age;
  }
}
```

### インターフェース
* inteface宣言で型定義できるのはオブジェクト型のみ(type文はプリミティブ型も定義可能)
```typescript
// 型引数を使ってUserInterfaceを定義
interface UserInterface<T> {
  name: T;
  age: number;
}

class User implements UserInterface<string> {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}
```

### アクセス修飾子
* アクセス修飾子には`private`、`protected`、`public`の3種類
* アクセス修飾子を記述しなければ`public`扱い
```typescript
class User {
  name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  public isAdult(): boolean {
    return this.age >= 20;
  }
}
```

## 参考
https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript-%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-Boris-Cherny/dp/4873119049

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80-%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7-Software-Design-plus/dp/4297127474

https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a

https://knmts.com/as-a-engineer-52/

https://www.typescriptlang.org/static/TypeScript%20Types-ae199d69aeecf7d4a2704a528d0fd3f9.png