TypeScriptの中級コース～TypeScriptにどっぷり浸かろう！～


## TypeScriptを極めよう！

TypeScriptは次世代のVBAになるほどMicrosoftがプッシュしています。
TypeScriptからファイルシステムにアクセスすることはできませんが
PowerAutomateと一緒に使うことで高度な処理が実現できます。

それではいきましょう！

## 1. 型推論の高度な使用法

TypeScriptの型推論は非常に強力です。複雑な型推論の例を見てみましょう。

```typescript
function createPair<T, U>(v1: T, v2: U): [T, U] {
  return [v1, v2];
}

let pair = createPair("hello", 42);
// pairの型は [string, number] と推論されます
```

## 2. 条件付き型の応用

条件付き型を使用して、入力に基づいて型を動的に選択できます。

```typescript
type TypeName<T> = 
    T extends string ? "string" :
    T extends number ? "number" :
    T extends boolean ? "boolean" :
    T extends undefined ? "undefined" :
    T extends Function ? "function" :
    "object";

type T0 = TypeName<string>;  // "string"
type T1 = TypeName<"a">;     // "string"
type T2 = TypeName<true>;    // "boolean"
type T3 = TypeName<() => void>;  // "function"
type T4 = TypeName<string[]>;    // "object"
```

## 3. マップ型と高度な型変換

マップ型を使用して、既存の型から新しい型を作成できます。

```typescript
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

type Partial<T> = {
    [P in keyof T]?: T[P];
};

interface Person {
    name: string;
    age: number;
}

type ReadonlyPerson = Readonly<Person>;
// { readonly name: string; readonly age: number; }

type PartialPerson = Partial<Person>;
// { name?: string; age?: number; }
```

## 4. 高度なジェネリック制約

ジェネリック型に複雑な制約を適用できます。

```typescript
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // プロパティ 'length' は存在します
    return arg;
}

loggingIdentity(3);  // エラー、numberには 'length' プロパティがありません
loggingIdentity({length: 10, value: 3});  // OK
```

## 5. 型の交差と合成

型の交差を使用して、複数の型を組み合わせることができます。

```typescript
interface ErrorHandling {
    success: boolean;
    error?: { message: string };
}

interface ArtworksData {
    artworks: { title: string }[];
}

type ArtworksResponse = ArtworksData & ErrorHandling;

let response: ArtworksResponse = {
    artworks: [{ title: "Mona Lisa" }],
    success: true
};
```

## 6. 高度なインデックス型

インデックス型を使用して、オブジェクトのプロパティを動的に参照できます。

```typescript
function pluck<T, K extends keyof T>(o: T, propertyNames: K[]): T[K][] {
  return propertyNames.map(n => o[n]);
}

interface Car {
    manufacturer: string;
    model: string;
    year: number;
}

let taxi: Car = {
    manufacturer: 'Toyota',
    model: 'Camry',
    year: 2014
};

let makeAndModel = pluck(taxi, ['manufacturer', 'model']);
// makeAndModelの型は (string | number)[]
```

## 7. 型ガードとアサーション関数

カスタム型ガードを作成して、より精密な型チェックを行うことができます。

```typescript
interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

function isFish(pet: Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

function move(pet: Fish | Bird) {
    if (isFish(pet)) {
        pet.swim();
    } else {
        pet.fly();
    }
}
```

## 8. 再帰型

再帰型を使用して、ネストされたデータ構造を表現できます。

```typescript
type JSONValue = 
    | string
    | number
    | boolean
    | null
    | JSONValue[]
    | { [key: string]: JSONValue };

const data: JSONValue = {
    name: "John",
    age: 30,
    isStudent: false,
    hobbies: ["reading", "swimming"],
    address: {
        street: "123 Main St",
        city: "Anytown"
    }
};
```

## 9. テンプレートリテラル型の高度な使用法

テンプレートリテラル型を使用して、文字列ベースの複雑な型を作成できます。

```typescript
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";

type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"

type Lang = "en" | "ja" | "pt";

type LocaleMessageIDs = `${Lang}_${AllLocaleIDs}`;
// "en_welcome_email_id" | "en_email_heading_id" | "en_footer_title_id" | "en_footer_sendoff_id" |
// "ja_welcome_email_id" | "ja_email_heading_id" | "ja_footer_title_id" | "ja_footer_sendoff_id" |
// "pt_welcome_email_id" | "pt_email_heading_id" | "pt_footer_title_id" | "pt_footer_sendoff_id"
```

## 10. 高度な型レベルプログラミング

TypeScriptの型システムを使用して、複雑な計算を型レベルで実行できます。

```typescript
type Subtract<T extends number, U extends number> = 
    [...Array<T>]['length'] extends [...Array<U>, ...infer Rest] 
    ? Rest['length'] 
    : never;

type Result = Subtract<5, 3>; // 2

type Fibonacci<N extends number, A extends number[] = [1], B extends number[] = [1]> = 
    N extends 0 ? 0 :
    N extends 1 ? 1 :
    N extends 2 ? 1 :
    A['length'] extends N ? B['length'] :
    Fibonacci<N, B, [...A, ...B]>;

type Fib5 = Fibonacci<5>; // 5
type Fib10 = Fibonacci<10>; // 55
```

これらの高度な型システムの機能を理解し活用することで、より堅牢で表現力豊かなTypeScriptコードを書くことができます。型システムを深く理解することは、バグの早期発見やコードの自己文書化につながり、大規模なアプリケーション開発において非常に有益です。