Typescriptについて

## TypeScriptとは
**型がついたJavaScript**です。コンパイルすることでJavascriptになります。マイクロソフトが開発しました。

## TypeScriptを使う理由

#### コードの信頼性向上
静的型付けが採用されているため、コードのバグを事前に検知できます。また、IDEやエディターなどの開発ツールによる補完や型チェックによって、コードの正確性を向上させることができます。

#### メンテナンス(型安全性)性の向上
型の整合性がチェックされるため、実行時に型エラーが発生する可能性が減ります。これでコードの品質が向上し、バグの発生率が下がります。コードの可読性が向上し、メンテナンス性も高まるのです。特に大規模なアプリケーションの開発で力を発揮するようです。

#### JavaScriptとの親和性
JavaScriptのスーパーセットとして開発されているため、JavaScriptのコードをそのまま利用することができます。また、ブラウザで実行できるため、既存のJavaScriptコードと共存させることができます。

※スーパーセットとは、ある言語やフォーマットなどが、**別の言語やフォーマットを基にして機能を追加したもの**です。TypeScriptはJavaScriptのスーパーセットです。つまり、TypeScriptはJavaScriptを基にして開発された言語で、JavaScriptの機能に加えて、静的型付けやクラス定義、インターフェースなどの機能が追加されています。なので、TypeScriptはJavaScriptの機能をすべて含み、加えて静的型付けなどの新しい機能を提供する言語となっています。


## 文法の特徴

#### 型注釈
JavaScriptには動的型付けが採用されているため、変数や関数の型がコード上では明示されません。TypeScriptは、変数や関数の前に型注釈をつけることで、静的型付けを実現しています。例えば、変数xが数値であることを明示する場合は、`let x:number`と記述します。

#### インターフェース
JavaScriptではオブジェクトの型を定義するために、オブジェクトリテラルでプロパティを列挙する方法があります。TypeScriptでは、このような方法の他に「インターフェース」という機能を提供しています。インターフェースを使うことで、プロパティの名前や型を明示的に定義できます(インターフェースについては後ほど記載します)

#### クラス
JavaScriptにはクラス機能がありますが、TypeScriptでは**クラスに対する型定義がサポートされています**。また、クラスのプロパティやメソッドに対するアクセス修飾子（public、private、protected）もサポートされています。

## 文法
`let`や`const`を使用して変数を宣言します。stringの値の代入はシングルクオートでも可能です。
```typescript
let foo: string = "bar"; // 文字列型の変数fooを宣言
const num: number = 123; // 数値型の定数numを宣言
```

#### 型注釈
変数や関数、オブジェクトに対して直接型を指定する方法です。先程説明した、基礎的な記述です。変数の後に`:`をつけて型を指定します。
```typescript
let num: number = 10;
let str: string = "hello";
let bool: boolean = true;
```

#### 型推論
TypeScriptが自動的に変数や関数、オブジェクトなどの型を推論する方法です。例えば、以下のように変数を宣言する場合、TypeScriptは自動的にその型を推論します。
```typescript
let num = 10;
let str = "hello";
let bool = true;
```
この場合、TypeScriptはそれぞれの変数を`number型`、`string型`、`boolean型`として推論します。型推論によってコードを短く簡潔に書くことができますが、推論結果が意図したものと異なる場合や複雑な型の場合、「型注釈」を使用します。型注釈と型推論を適切に使い分けることで、TypeScriptの静的型チェックを活用した信頼性の高いコードが書けます。

## 関数宣言
関数を宣言するには、引数と戻り値の型を指定します。
```typescript
function add(a: number, b: number): number {
  return a + b;
}
```

### アロー関数
```typescript
const multiply = (a: number, b: number): number => {
  return a * b;
}
```

### インターフェース
インターフェースを定義することで、オブジェクトの型を定義できます。
```typescript
interface User {
  name: string;
  age: number;
  email?: string; // ?をつけることで、任意項目になります
}

const user: User = {
  name: "John",
  age: 30,
  email: "john@example.com"
};
```

### インターフェースの継承
継承されたインターフェースのプロパティやメソッドは、新しいインターフェースでも利用することができます。
```typescript
// Shapeインターフェースの定義
interface Shape {
  // 面積を返すgetAreaメソッドを定義
  getArea(): number;
}

// Rectangleインターフェースの定義
interface Rectangle extends Shape {
  width: number;
  height: number;
}

// MyRectangleクラスの定義
class MyRectangle implements Rectangle {
  width: number;
  height: number;

  // コンストラクター
  constructor(width: number, height: number) {
    this.width = width;
    this.height = height;
  }

  // 面積を計算するメソッドを定義
  getArea() {
    return this.width * this.height;
  }
}

// MyRectangleクラスのインスタンスを作成し、面積を計算して出力
const myRect = new MyRectangle(10, 20);
console.log(myRect.getArea()); // 200
```

## TypeScriptの型推論
なお、TypeScriptの型推論は様々な場面で利用されます。以下にいくつかまとめます。
```typescript
// 数値リテラル型
let num: 10; // numは10しか代入できない

// 文字列リテラル型
let str: "Hello"; // strは"Hello"しか代入できない

// booleanリテラル型
let bool: true; // boolはtrueしか代入できない

// any型
let anyVar: any; // どんな型でも代入できる

// unknown型
let unknownVar: unknown; // どんな型でも代入できるが、型の安全性を保つためには型チェックが必要

// void型
function voidFunc(): void {
  console.log("This function returns nothing.");
}

// never型
function errorFunc(): never {
  throw new Error("This function throws an error.");
}

// object型
let obj: object; // どんなオブジェクトでも代入できるが、具体的な型は不明

// プリミティブ型
let num1 = 1; // number型
let str1 = "hello"; // string型
let bool1 = true; // boolean型

// 配列型
let numArr = [1, 2, 3]; // number型の配列
let strArr = ["hello", "world"]; // string型の配列

// タプル型
let tuple: [string, number] = ["hello", 10]; // 最初の要素はstring型、次の要素はnumber型

// オブジェクト型
let obj1: { name: string; age: number } = { name: "John", age: 30 }; // nameプロパティはstring型、ageプロパティはnumber型

// 関数型
function add(x: number, y: number): number {
  return x + y;
}

// ジェネリック型
function identity<T>(arg: T): T {
  return arg;
}
let num = identity<number>(10); // 型パラメータにnumberを指定
let str = identity<string>("hello"); // 型パラメータにstringを指定
```
※ジェネリック型は、汎用的な型を定義し、様々な型の値を受け取ります。ジェネリック型を使うことで、**特定の型に限定されない汎用的な関数やクラス**を実装することができます。`<T>`のように、`<>`で囲んだ型パラメータを使って定義されます。この型パラメータには、任意の名前を付けることができますが、一般的にはTがよく使われます。

なお、`identity関数`は、引数として受け取った値をそのまま返すだけの単純な関数ですが、型パラメータ`<T>`を使うことで、引数の型を自由に指定できます。**型に依存しない柔軟な関数**を実装できるわけですね。

以上です。次回は「型」について記載しようと思います。