mcpField
T
typescript-pro

typescript-pro

github.com/404kidwiz開発109 回インストール
リポジトリ

typescript-pro について

typescript-proは、複雑な型や型安全なAPI、JavaScriptからの移行に取り組む開発者向けのTypeScriptスキルです。高度な型設計、問題の調査、大規模プロジェクトのビルド性能に関するワークフローを扱います。

主な機能

  1. 01高度なジェネリクスとマップ型
  2. 02型安全なAPI設計
  3. 03段階的なJavaScript移行
  4. 04型エラーと推論の調査
  5. 05TypeScriptビルド性能の指針

活用シーン

  1. 01再利用可能な型システムの設計
  2. 02アプリケーション層間でのAPI型共有
  3. 03大規模なJavaScriptコードベースの移行
  4. 04複雑なコンパイラーエラーの診断

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/404kidwiz/claude-supercode-skills --skill typescript-pro

インストール後、Claude Code で/typescript-proを入力して読み込まれたか確認します。

詳細

TypeScript プロスペシャリスト

目的

高度な型システム機能、ジェネリックプログラミングのパターン、型安全なアプリケーションアーキテクチャを活用した、専門的な TypeScript 開発機能を提供します。TypeScript 5+ を活用し、包括的な型安全性を備えた堅牢で保守しやすいアプリケーションの構築を専門としています。

使用する場面

  • 高度なジェネリクスやマップ型を用いた複雑な型システムの設計
  • フロントエンドとバックエンドの境界をまたぐ型安全な API の実装
  • JavaScript のコードベースを段階的に TypeScript へ移行
  • 複雑な型エラーや型推論の問題のトラブルシューティング
  • 型安全なライブラリ、SDK、フレームワーク連携の構築
  • 大規模プロジェクトにおける TypeScript のビルドパフォーマンスの最適化
  • ブランド型、判別可能なユニオン型、ユーティリティ型の作成

クイックスタート

次の場合にこのスキルを呼び出します:

  • 高度なジェネリクスやマップ型を用いた複雑な型システムの設計
  • フロントエンドとバックエンドの境界をまたぐ型安全な API の実装
  • JavaScript のコードベースを段階的に TypeScript へ移行
  • 複雑な型エラーや型推論の問題のトラブルシューティング
  • 型安全なライブラリ、SDK、フレームワーク連携の構築

次の場合は呼び出さないでください:

  • 単純な JavaScript のタスク(型注釈が不要)
  • 実行時のロジックのバグ(代わりにデバッガーを使用)
  • ビルド設定のみの作業(代わりに build-engineer を使用)
  • React/Vue 固有のパターン(react-specialist/vue-expert を使用)


中核となるワークフロー

ワークフロー 1:型安全な API クライアントの設計

ユースケース: 自動補完機能を備えた、完全に型安全な REST API クライアントを作成する

手順:

1. API スキーマを定義する(コントラクトファースト)

// api-schema.ts - Single source of truth for API contract
export const apiSchema = {
  '/users': {
    GET: {
      query: {} as { page?: number; limit?: number },
      response: {} as { users: User[]; total: number }
    },
    POST: {
      body: {} as { email: string; name: string },
      response: {} as { id: string; email: string; name: string }
    }
  },
  '/users/{id}': {
    GET: {
      params: {} as { id: string },
      response: {} as User
    },
    PUT: {
      params: {} as { id: string },
      body: {} as Partial<User>,
      response: {} as User
    },
    DELETE: {
      params: {} as { id: string },
      response: {} as { success: boolean }
    }
  },
  '/posts': {
    GET: {
      query: {} as { author_id?: string; tags?: string[] },
      response: {} as { posts: Post[]; next_cursor?: string }
    }
  }
} as const;

// Extract types from schema
type ApiSchema = typeof apiSchema;
type ApiPaths = keyof ApiSchema;
type ApiMethods<Path extends ApiPaths> = keyof ApiSchema[Path];

// Helper types for type-safe request/response
type RequestParams<
  Path extends ApiPaths,
  Method extends ApiMethods<Path>
> = ApiSchema[Path][Method] extends { params: infer P } ? P : never;

type RequestQuery<
  Path extends ApiPaths,
  Method extends ApiMethods<Path>
> = ApiSchema[Path][Method] extends { query: infer Q } ? Q : never;

type RequestBody<
  Path extends ApiPaths,
  Method extends ApiMethods<Path>
> = ApiSchema[Path][Method] extends { body: infer B } ? B : never;

type ResponseData<
  Path extends ApiPaths,
  Method extends ApiMethods<Path>
> = ApiSchema[Path][Method] extends { response: infer R } ? R : never;

2. 型安全な API クライアントを実装する

// api-client.ts
class ApiClient {
  constructor(private baseUrl: string) {}

  async request<
    Path extends ApiPaths,
    Method extends ApiMethods<Path>
  >(
    path: Path,
    method: Method,
    options?: {
      params?: RequestParams<Path, Method>;
      query?: RequestQuery<Path, Method>;
      body?: RequestBody<Path, Method>;
    }
  ): Promise<ResponseData<Path, Method>> {
    // Replace path parameters: /users/{id} → /users/123
    let url = path as string;
    if (options?.params) {
      Object.entries(options.params).forEach(([key, value]) => {
        url = url.replace(`{${key}}`, String(value));
      });
    }

    // Append query parameters
    if (options?.query) {
      const queryString = new URLSearchParams(
        options.query as Record<string, string>
      ).toString();
      url += `?${queryString}`;
    }

    // Make request
    const response = await fetch(`${this.baseUrl}${url}`, {
      method: method as string,
      headers: {
        'Content-Type': 'application/json',
      },
      body: options?.body ? JSON.stringify(options.body) : undefined,
    });

    if (!response.ok) {
      throw new Error(`API Error: ${response.status}`);
    }

    return response.json();
  }
}

// Usage with full type safety and auto-completion
const api = new ApiClient('https://api.example.com');

// GET /users?page=1&limit=10
const usersResponse = await api.request('/users', 'GET', {
  query: { page: 1, limit: 10 }  // Type-checked!
});
usersResponse.users[0].email;  // ✅ Auto-complete works!

// POST /users
const newUser = await api.request('/users', 'POST', {
  body: { email: '[email protected]', name: 'Test' }  // Type-checked!
});
newUser.id;  // ✅ Type: string

// PUT /users/{id}
const updatedUser = await api.request('/users/{id}', 'PUT', {
  params: { id: '123' },  // Type-checked!
  body: { name: 'Updated Name' }  // Partial<User> type-checked!
});

// TypeScript errors for invalid usage:
api.request('/users', 'GET', {
  query: { invalid: true }  // ❌ Error: Object literal may only specify known properties
});

api.request('/users/{id}', 'PUT', {
  // ❌ Error: params required for this path
  body: { name: 'Test' }
});

3. Zod による実行時検証を追加する

import { z } from 'zod';

// Define Zod schemas for runtime validation
const UserSchema = z.object({
  id: z.string().uuid(),
  email: z.string().email(),
  name: z.string().min(1).max(100),
  created_at: z.string().datetime()
});

type User = z.infer<typeof UserSchema>;  // TypeScript type from Zod schema

// Enhanced API client with runtime validation
class ValidatedApiClient extends ApiClient {
  async request<
    Path extends ApiPaths,
    Method extends ApiMethods<Path>
  >(
    path: Path,
    method: Method,
    options?: {
      params?: RequestParams<Path, Method>;
      query?: RequestQuery<Path, Method>;
      body?: RequestBody<Path, Method>;
      responseSchema?: z.ZodSchema<ResponseData<Path, Method>>;
    }
  ): Promise<ResponseData<Path, Method>> {
    const response = await super.request(path, method, options);

    // Runtime validation if schema provided
    if (options?.responseSchema) {
      return options.responseSchema.parse(response);
    }

    return response;
  }
}

// Usage with runtime validation
const validatedApi = new ValidatedApiClient('https://api.example.com');

const user = await validatedApi.request('/users/{id}', 'GET', {
  params: { id: '123' },
  responseSchema: UserSchema  // Runtime validation!
});
// If API returns invalid data, Zod throws detailed error


ワークフロー 3:TypeScript への段階的な移行

ユースケース: 大規模な JavaScript コードベースを段階的に移行する

フェーズ 1:変更を加えずに TypeScript を有効にする(第 1 週)

// tsconfig.json - Initial configuration
{
  "compilerOptions": {
    "allowJs": true,          // Allow .js files
    "checkJs": false,         // Don't check .js files yet
    "noEmit": true,           // Don't output files (just check)
    "skipLibCheck": true,     // Skip type checking of .d.ts files
    "esModuleInterop": true,
    "moduleResolution": "node",
    "target": "ES2017",
    "module": "commonjs"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

フェーズ 2:JSDoc の型ヒントを追加する(第 2~4 週)

// user.js - Add JSDoc comments for type checking
/**
 * @typedef {Object} User
 * @property {string} id
 * @property {string} email
 * @property {string} name
 */

/**
 * Fetch user by ID
 * @param {string} userId
 * @returns {Promise<User>}
 */
async function getUserById(userId) {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

/**
 * @param {User[]} users
 * @param {string} searchTerm
 * @returns {User[]}
 */
function filterUsers(users, searchTerm) {
  return users.filter(u => u.name.includes(searchTerm));
}

フェーズ 3:checkJs を段階的に有効にする(第 5~8 週)

// tsconfig.json - Start checking JavaScript
{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,  // ✅ Enable type checking for .js files
    "noEmit": true
  }
}

ディレクトリごとにエラーを修正する:

# Disable checkJs for specific files with errors
// @ts-nocheck at top of file

# Or suppress specific errors
// @ts-ignore
const result = unsafeOperation();

フェーズ 4:ファイルを TypeScript にリネームする(第 9~12 週)

# Rename .js → .ts one directory at a time
mv src/utils/user.js src/utils/user.ts

# Update imports (no file extensions in TypeScript)
- import { getUserById } from './user.js'
+ import { getUserById } from './user'

明示的な型を追加する:

// user.ts - Full TypeScript with explicit types
interface User {
  id: string;
  email: string;
  name: string;
  created_at: Date;
}

async function getUserById(userId: string): Promise<User> {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

function filterUsers(users: User[], searchTerm: string): User[] {
  return users.filter(u => u.name.includes(searchTerm));
}

フェーズ 5:厳格モードを有効にする(第 13~16 週)

// tsconfig.json - Enable strict mode progressively
{
  "compilerOptions": {
    "strict": true,  // Enable all strict checks
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true
  }
}

厳格モードのエラーを修正する:

// Before (implicit any)
function processData(data) {  // ❌ Parameter 'data' implicitly has 'any' type
  return data.map(item => item.value);
}

// After (explicit types)
function processData(data: Array<{ value: number }>): number[] {
  return data.map(item => item.value);
}

// Before (null not handled)
function getUserName(user: User) {  // ❌ User might be null
  return user.name;
}

// After (null handled)
function getUserName(user: User | null): string {
  return user?.name ?? 'Unknown';
}


パターン 2:文字列検証のためのテンプレートリテラル型

使用場面: CSS クラス名、API ルート、環境変数

// Type-safe CSS class names
type Size = 'sm' | 'md' | 'lg';
type Color = 'red' | 'blue' | 'green';
type ClassName = `btn-${Size}-${Color}`;

function createButton(className: ClassName) {
  return `<button class="${className}"></button>`;
}

createButton('btn-md-blue');  // ✅ Valid
createButton('btn-xl-yellow');  // ❌ Error: Not assignable to ClassName

// Type-safe environment variables
type Stage = 'dev' | 'staging' | 'prod';
type Region = 'us' | 'eu' | 'asia';
type Environment = `${Stage}_${Region}`;

const env: Environment = 'prod_us';  // ✅ Valid
const invalid: Environment = 'production_us';  // ❌ Error


❌ アンチパターン 2:戻り値の型を定義しない

どのようなものか:

function getUser(id: string) {  // ❌ No return type
  return fetch(`/api/users/${id}`).then(r => r.json());
}
// Return type inferred as Promise<any>

問題点:

  • 実装を変更すると、戻り値の型も気付かないうちに変わります
  • 関数が何を返すか保証されません
  • 互換性を損なう変更を検出しにくくなります

適切な方法:

interface User {
  id: string;
  email: string;
  name: string;
}

function getUser(id: string): Promise<User> {  // ✅ Explicit return type
  return fetch(`/api/users/${id}`).then(r => r.json());
}


連携パターン

typescript-pro ↔ react-specialist
  • 引き継ぎ:TypeScript プロが型を定義し、React スペシャリストがコンポーネントで使用します
  • 連携:props、state、API コントラクトの型定義を共有します
  • ツール:型には TypeScript、UI ロジックには React を使用します
typescript-pro ↔ backend-developer
  • 引き継ぎ:TypeScript プロが API の型を設計し、バックエンド開発者が対応する型を実装します
  • 連携:スキーマ定義(OpenAPI、tRPC、GraphQL)を共有します
  • 共同責任:エンドツーエンドの型安全性
typescript-pro ↔ nextjs-developer
  • 引き継ぎ:TypeScript の型を Next.js App Router のサーバー/クライアントコンポーネントに適用します
  • 連携:Server Actions の型、API ルートの型
  • 依存関係:Next.js は TypeScript の恩恵を大きく受けます

コメント