TypeScriptの基本文法についてのメモ

# はじめに
TypeScriptの基本文法についてのメモ

# 参考
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/ref=sr_1_2_sspa?crid=1TO3871EL5COQ&keywords=typescript&qid=1697037283&s=books&sprefix=type%2Cstripbooks%2C195&sr=1-2-spons&sp_csd=d2lkZ2V0TmFtZT1zcF9hdGY&psc=1

# TypeScriptの特徴
* JavaScriptに静的型付けシステムとクラスベースのオブジェクト指向を加えた上位互換の言語
* 型チェック、型安全性: 間違ったプログラムをコンパイラが型チェックで検出してくれる
* 型推論:　型を書かなくても言語処理系が文脈から型を予想して型付けしてくれる



# 設定ファイルtsconfig.json
* TypeScriptコンパイラに対する設定を記述したファイル
* tscはtsconfig.jsonを自動的に読み込み、それに従ってコンパイルを実行

# TypeScriptの文法
## 型アノテーション(型注釈)
* 変数に型を指定すること
* 型の不整合があると、コンパイル時にチェックされる

```typescript
const 変数:　型 = 式;
```

コンパイラがその文脈から型を推測できる場合は、型アノテーションを省略しても自動的に保管して解釈してくれる

# TypeScript固有の特殊な型
* unknown型
  * 方が不明である
  * 通常、型チェックしてから利用する

* null許容型
  * strictNullChecksオプションが有効の場合、null/undefinedを禁止できる
  * その時に、明示的にstring | null を使うとnullを認めることになる

# 関数コンポーネントの型定義
最近の TypeScript + React のベストプラクティスとして、FC を使わずに明示的に型定義する 方法が推奨

children の型を不要な場合に含めないことで、より厳密な型定義が可能。
戻り値の型を JSX.Element で明示できる。

```react


import React from 'react';

// childrenを使わない時
type Props = {
  name: string;
};

// childrenを使うときは明示的に用意する
type Props = {
  name: string;
  children?: React.ReactNode;
};

const Greeting = ({ name }: Props): JSX.Element => {
  return <h1>Hello, {name}!</h1>;
};

export default Greeting;
```


```react
// FC型のコンポーネントを定義
// propsの定義も上記の用にすれば良いので、わざわざFC型定義をつかわない方を推奨しているｍ
const MyComponent: FC<Props> = ({ title, description, children }) => {
  return (
    <div>
      <h1>{title}</h1>
      {description && <p>{description}</p>}
      {children}
    </div>
  );
};

// 追加プロパティの設定
// 使う用途なし
MyComponent.displayName = "CustomComponent";  // コンポーネント名の指定
MyComponent.defaultProps = {
  description: "This is a default description"
};

export default MyComponent;
```
# 拡張子 .ts .tsx
* tsはJSXを含まない
* tsxはJSXを含む

明示的に区別したほうがよい

## 比較演算子

`==`は異なる型の比較した場合、暗黙の型変換をおこなってから両者を比較するためtrueになることがある。厳密に比較は`===`を使う。

```typescript
console.log(str === 3)
```

## 論理演算子
```typescript
x && y 
x || y
x ?? y
```

  * x && y 
     * xを真偽値に変換した結果、trueならyを返す、falseならx
  * x || y 
     * xを真偽値に変換した結果、falseならyを返す、trueならx

  * x ?? y
     * xがnullまたはundefinedのときのみyを返す   
     * (||は0、falseなどの値もないものとして扱ってしまう)
     * データがない場合は代替の値を使う、というシチュエーションに適している

## オブジェクト
ここではクラスに由来しないオブジェクトのこと

```typescript
// 省略記法
// プロパティと変数名が同じ場合
{name}
//動的なプロパティの決定
// インデックスシグネチャ
//[変数名: 型]
const obj = {
[name: string]: 123
}
```
インデックスシグネチャを使うと存在しないプロパティへのアクセスなどはコンパイルエラーにならず、型安全性が壊れてしまう。なので極力使わないほうがよさそう。

* オブジェクト型

```typescript
const obj: {
foo: number,
bar: string
}
= {
foo: 1,
bar: "abc"
}
```
* type文で型に別名をつける
```typescript

type FoobarObj ={
foo: number,
bar: string
}
const obj: FoobarObj
= {
foo: 1,
bar: "abc"
}
```

* typofキーワード
　　* 型なし変数の型推論を抽出して使うことができる。
 * ただ、型は明示的に記載するべきなので、あまりtypeofを利用しないほうがよい

### 型引数
型を作成するときにパラメータを付与することができる

```typescript
type USer<T>={
name: string,
child: T
}
```

このときThahasName型の部分型でなければいけない

```typescript
type USer<T extends hasName>={
name: string,
child: T
}
```


### const 
この場合はnameや、ageは再代入できるが、userに別のオブジェクトを再代入はできないということ
```typescript
const user ={
nam: "aaa",
age: 25,
}
```



## typeとinterface
* typeは任意の型に対して別名をつけることができる、interfaceはオブジェクト型のみ　
* typeのほうがよく使われるみたい

```typescript
const user ={
nam: "aaa",
age: 25,
}
type T = typeof user;
const obj2: T = ...
```

### typeof
型推論の結果を型として抽出、再利用する


### 部分型関係
ある型をほかの型の代わりに使える、ある型を他の型とみなせる


## 分割代入
* オブジェクトから値を取り出して、変数に代入する

```typescript
const {foo,bar} = obj;
```
* これはオブジェクトのプロパティの中身をプロパティと同名の変数に入れたい場合にしか使えない。が、多くの場合同名を使う

### ネストしたパターン
```typescript
const nested = {
num: 123,
obj: {
  foo: "heelo",
}
}

const {num, obj:{foo}} = nested
console.log(foo) // hello
```


## Enum
Enumを使うより、リテラル型でEnumを表現するほうがよく利用されている
```typescript
type Direction = "NORTH" | "SOUTH" | "EAST" | "WEST";

function move(direction: Direction) {
    // ...
}

move("NORTH");  // OK
move("SOUTHWEST");  // エラー: Argument of type '"SOUTHWEST"' is not assignable to parameter of type 'Direction'.
```

## タプル型
固定数の要素を持ち、それぞれの要素が異なる型を持つことができる配列のような型です。タプルは配列と似ていますが、要素の数とその型が固定されている点が異なります。

```typescript
let x: [string, number];
x = ["hello", 10]; // OK
```

## 関数の型定義
TypeScriptではコンパイラオプションに`noImplicitAny`が指定されていないと、引数の型定義がなくても暗黙のうちに`any`があてがわれてコンパイルが通ってしまうので、tsconfig.jsonにnoImplicityAnyの設定が必要

引数と戻り値をまとめて定義する方法

関数の型定義
```typescript
interface Greeter {
    (message: string, recipient: string): void;
}

const greet: Greeter = (msg, person) => {
    console.log(`${msg}, ${person}!`);
};
```

Reactの関数コンポーネントの型

```react
type TodoPresenterProps ={
    todos: Todo[]
}

// <>はpropsの型
export const TodoPresenter: React.FC<TodoPresenterProps> = ({todos,}) => {
  return (
    <div>
      
    </div>
  )
}
```

## ジェネリクスと型引数
型を具体的に指定せずにコンポーネントを定義し、それを使用する際に具体的な型を指定することができます

```typescript
//<T>がジェネリクス
function identity<T>(arg: T): T {
    return arg;
}

//<string>が型引数
let output = identity<string>("hello");

```
型推論で以下のようにもかける
```typescript
let output = identity("hello"); // string型が推論される
```

## 型引数
TypeScriptのジェネリクスの一部として提供される機能であり、型をパラメータとして関数やクラス、インタフェースなどに渡すことができます。これにより、汎用的で再利用可能なコードを記述することができるようになります。
特定の型に依存せず、かつ型の安全性を保持したままコードを実装することができます

```typescript
function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("hello");
let output2 = identity<number>(123);
```
identity関数は、型引数Tを持っており、入力としてT型の値を受け取り、同じT型の値を返します。この関数を呼び出す際に、具体的な型（この場合はstringやnumber）を指定することで、関数の挙動をその型に合わせることができます。


## ユニオン型とインターセクション型
ユニオン型
複数の型のうちのどれか一つの型を持つことができる構文
```typescript
type StringOrNumber = string | number;

let value: StringOrNumber;

value = "hello";  // OK
value = 123;      // OK
value = true;     // Error: boolean型はStringOrNumber型に代入できない
```
インターセクション型
複数の型を組み合わせて、それらのすべての特性を持つ新しい型を作成するために使用
オブジェクト型を拡張した新しい型を作る
```typescript
type Name = {
    name: string;
};

type Age = {
    age: number;
};

type Person = Name & Age;

let person: Person = {
    name: "Alice",
    age: 30
};
```

## オプショナルチェイニングによるプロパティアクセス
obj?.propの場合、objがnull、undefinedの場合でもランタイムエラーは発生せず、結果はundefinedになる

メソッドの場合はobj?.method()。

要するに簡潔に書ける

## リテラル型
文字、数値、真偽値、BigIntはリテラルをそのまま型として扱うことができる

```typescript
const foo: "foo" = "foo"; 
const two: 2 = 2;  //2型
const isTrue: true = true;
const bigIntValue: 123n = 123n;

//今までのように型指定してなくても、constは型推論でリテラル型にしていた
const name = "aaa"  // aaa型。なので再代入不可
```

## リテラル型のwidening
リテラル型が自動的に対応するプリミティブ型に変化する挙動

```typescript
// これはfoo型
const foo = "foo"; 
// これはstring型。プリミティブ型に変換される
// letで宣言された変数はあとで再代入されることが期待されるから
let foo = "foo";
// オブジェクトもプロパティは再代入可能なので、プリミティブ型になる
```

## 型のNull安全とは
* デフォルトの設定ではすべての型にnullとundefinedを代入できてしまう
* tstrictNullChecksを設定して、nullやundfinedを代入しているとコンパイルチェックされる
* null、undefinedを代入するには、型をstring | nullのように明示的に指定する必要がある

## 型のtypeof
変数の型をキャプチャして、他の変数の型として再利用することができます

```typescript
let person = {
    name: "Alice",
    age: 30
};

type PersonType = typeof person;

function greet(arg: PersonType) {
    console.log(`Hello, my name is ${arg.name} and I am ${arg.age} years old.`);
}
```
typeofをオブジェクトに適用して、オブジェクトの型を取得できる。

```typescript
const person = {
    name: "Alice",
    age: 30
};

type PersonType = typeof person;  // type PersonType = { name: string; age: number; }
```
typeof
typeof 変数名で型を取り出す。型推論されている型を抽出、再利用など

## 演算子のtypeof
実行時に変数のデータ型を文字列として取得 する。

```typescript
const value = "Hello";

console.log(typeof value); // "string"
console.log(typeof 123);   // "number"
console.log(typeof true);  // "boolean"

```
## keyof型
keyof 型　で型が例えばオブジェクトである場合、オブジェクトのプロパティ名全てを受け入れる型になる。A | B | C。

```typescript
type Human ={
name: string,
age: number
}
// "name" | "age"という型になる
type Humankeys = keof Human;
```
keyof typeof オブジェクトとして、オブジェクトの型から各プロパティ名を型として抽出するときによく使われる。


## 型ガード、型絞り込み
型ガードは、TypeScriptのコード内である変数やオブジェクトの型を確認または絞り込むためのパターンや構造です。型ガードを使用することで、特定のスコープ内でその変数の型が保証され、それに応じて安全にその変数を操作できます。
各条件分岐内では型が絞れていて、コンパイルエラーは起きない

```typescript
function padLeft(value: string | number) {
    if (typeof value === "string") {
        return `-${value}-`;
    } else {
        return value.toString();
    }
}
```
```typescript
class Bird {
    fly() {
        console.log("bird flies");
    }
}

class Dog {
    bark() {
        console.log("dog barks");
    }
}

function move(animal: Bird | Dog) {
    if (animal instanceof Bird) {
        animal.fly();
    } else {
        animal.bark();
    }
}
```

## as const
文字列、数値、BigInt、真偽値リテラルに対してつけられるリテラル型がプリミティブにwidenningしないリテラル型=readonlyになる

```typescript
// 中は書き換え可能なため、リテラル型がstringに置き換わる
// よって、string[]型 
const names1 = ["aaa","bbb","ccc"]

// constのため、書き換え不可(readonly)、さらにリテラル型のままになる
// readonly["aaa","bbb","ccc"] 型
const names1 = ["aaa","bbb","ccc"] as const
```

## モジュールとカプセル化
モジュール内で定義された変数はそのモジュール内をスコープとしてもつ。変数を変更できるのは、そのモジュール内だけから

## import export
```typescript
import { } from "モジュール名"
// export defaultの場合
import 変数名from "モジュール名"
```

## @types
TypeScriptでもジュルーが書かれていない場合に、@typesパッケージをインストールして型情報をインストールする

# 部分型
DogはAnimalの部分型
Animalが持つプロパティはすべて存在する。そのプロパティの方はAnimalの方の部分型または同じ型

**ある型を他の型の代わりに使える、ある方を他の型とみなせるという直感的な概念に基づくもの**


```typescript
type Animal = {
  name: string;
  age: number;
};

type Dog = {
  name: string;
  age: number;
  breed: string; // `Dog` は `Animal` に `breed` を追加した型
};

const dog: Dog = { name: "Buddy", age: 3, breed: "Golden Retriever" };
const animal: Animal = dog; // ✅ `Dog` は `Animal` の部分型なので代入可能
　　　　　　　　　　　　　　　　　// こうすることで制限できる

```

```typescript
// DogはAnimalの部分型
Dog extends Animal
```
## 型引数
* 型を定義するときにパラメータをもたせることができる
* 型引数を持つ型はジェナリクス型と呼ばれる

```typescript
// <>の中には型を指定する
// Parent、ChildはHasNameの部分型である
type Family<Parent extends HasName, Child extends HasName>

// Animal、HumanはHasnameの部分型
type T = Family<Animal, Human>


```

```typescript
type Animal = {
  name: string;
};

type Family<Parent = Animal, Child = Animal> = {
  parent: Parent;
  child: Child;
};
```

## 帰り値の型による部分型関係
引数の型が同じでないといけない

```typescript
type Response = {
  status: number;
  message: string;
};

type SuccessResponse = {
  status: 200;
  message: "OK";
  data: string;
};

function fetchResponse(): Response {
  return { status: 500, message: "Server Error" };
}

function fetchSuccessResponse(): SuccessResponse {
  return { status: 200, message: "OK", data: "All good!" };
}

let apiCall: () => Response;

// ✅ OK（SuccessResponse は Response の部分型）
apiCall = fetchSuccessResponse;

```

## keyof typeof
typeofで型を抜き出して、keyofで型のプロパティ名を型として取り出す

```typescript
const STATUS = {
  SUCCESS: 200,
  ERROR: 500,
} as const;

type Status = keyof typeof STATUS; // "SUCCESS" | "ERROR"

type Response = {
  status: Status;
  message: string;
};

const fetchResponse = (): Response => ({
  status: "SUCCESS",
  message: "Operation completed!",
});

let apiCall: () => Response;

// ✅ OK
apiCall = fetchResponse;
```

## Lookup 型

T[K] のように書くことで、
型 T の中から特定のキー K の型を取得する仕組みです。
これは オブジェクト型の特定のプロパティの型を動的に参照する のに使われます。

同じことを2度書かないし。プロパティの型を指定することで、プロパティが変わったとしても修正が必要ないのｄ
```typescript
type User = {
  id: number;
  name: string;
  email: string;
};

// Lookup 型を使って `User["name"]` の型を取得
type UserName = User["name"]; // string
```

## 型コンテキストのIn演算子

```typescript
if ("プロパティ名" in オブジェクト) {
  // ここでは "プロパティ名" があることが保証される
}
```

```typescript
type User = {
  id: number;
  name: string;
  email: string;
};

// マップ型を使って全プロパティをオプショナルにする
type PartialUser = {
  [K in keyof User]?: User[K];
};

// ✅ PartialUser の型
// {
//   id?: number;
//   name?: string;
//   email?: string;
// }

const user: PartialUser = { name: "Alice" }; // ✅ OK（すべてオプショナル）

```