typescript-pro について
typescript-proは、複雑な型や型安全なAPI、JavaScriptからの移行に取り組む開発者向けのTypeScriptスキルです。高度な型設計、問題の調査、大規模プロジェクトのビルド性能に関するワークフローを扱います。
主な機能
- 01高度なジェネリクスとマップ型
- 02型安全なAPI設計
- 03段階的なJavaScript移行
- 04型エラーと推論の調査
- 05TypeScriptビルド性能の指針
活用シーン
- 01再利用可能な型システムの設計
- 02アプリケーション層間でのAPI型共有
- 03大規模なJavaScriptコードベースの移行
- 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 の恩恵を大きく受けます