typescript について
型のパターン、設定、コード品質に関する指針をまとめた TypeScript リファレンススキルです。言語の基礎から本番運用や問題解決まで扱います。
主な機能
- 01基本型、ジェネリクス、ユーティリティ型
- 02型ガードと高度なパターン
- 03厳格なコンパイラー設定
- 04Lint と本番対応のガイド
活用シーン
- 01アプリケーションデータの型選定
- 02厳格な TypeScript プロジェクトの設定
- 03よくある型エラーの調査
MCP 対応
より包括的な TypeScript ドキュメントを取得するための MCP ドキュメントツールに言及しています。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ claude-dev-suite/ claude-dev-suite --skill typescriptインストール後、Claude Code で/typescriptを入力して読み込まれたか確認します。
同梱ファイルquick-ref/generics.mdquick-ref/utility-types.md
詳細
TypeScript のコア知識
詳細な知識:包括的なドキュメントを参照するには、technology:
typescriptを指定してmcp__documentation__fetch_docsを使用してください。
基本型
// Primitives
const str: string = 'hello';
const num: number = 42;
const bool: boolean = true;
const arr: number[] = [1, 2, 3];
const tuple: [string, number] = ['hello', 42];
// Objects
interface User {
id: number;
name: string;
email?: string; // Optional
readonly createdAt: Date;
}
type Status = 'active' | 'inactive' | 'pending'; // Union
ジェネリクス
// Generic function
function identity<T>(arg: T): T {
return arg;
}
// Generic interface
interface Repository<T> {
find(id: string): Promise<T | null>;
findAll(): Promise<T[]>;
create(data: Omit<T, 'id'>): Promise<T>;
}
// Generic constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
ユーティリティ型
Partial<T> // All properties optional
Required<T> // All properties required
Pick<T, K> // Select properties
Omit<T, K> // Remove properties
Record<K, V> // Key-value map
Readonly<T> // All properties readonly
ReturnType<F> // Function return type
Parameters<F> // Function parameters
Awaited<T> // Unwrap Promise
高度なパターン
// Discriminated unions
type Result<T> =
| { success: true; data: T }
| { success: false; error: Error };
// Type guards
function isUser(obj: unknown): obj is User {
return typeof obj === 'object' && obj !== null && 'id' in obj;
}
// Mapped types
type Nullable<T> = { [K in keyof T]: T[K] | null };
// Template literals
type EventName = `on${Capitalize<string>}`;
設定(tsconfig.json)
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"moduleResolution": "bundler"
}
}
このスキルを使用しないケース
| シナリオ | 代わりに使用 |
|---|---|
| 純粋な JavaScript プロジェクト | javascript スキル |
| Node.js ランタイムの内部実装 | nodejs スキル |
| React 固有の型 | frontend-react スキル |
| 型アサーションのテスト | testing-vitest または testing-jest スキル |
| スキーマからの型生成 | api-design-openapi またはフレームワーク固有のスキル |
アンチパターン
| アンチパターン | 問題点 | 正しいアプローチ |
|---|---|---|
あらゆる場所で any を使用する | 型安全性が損なわれます | unknown または適切な型を使用する |
as による型アサーション | 実行時エラーが発生する可能性があります | 型ガードまたは適切な型付けを使用する |
| 大きなユニオン型 | 保守が困難になります | 判別可能なユニオンまたはブランド型を使用する |
interface と type を混在させる | コードベースに一貫性がなくなります | どちらかの規約を選ぶ |
| strictNullChecks を無視する | null/undefined に関する問題が隠れます | strict モードを有効にする |
| 範囲を制限しないインデックスシグネチャ | 安全でないアクセスにつながります | 検証付きの Record または Map を使用する |
| ジェネリクスを深くネストする | 型が読みにくくなります | 中間型を切り出す |
よくある問題の解決方法
| 問題 | 原因 | 解決策 |
|---|---|---|
| "Type 'X' is not assignable to type 'Y'" | 型の不一致 | 型定義を確認し、型ガードを使用する |
| "Property 'x' does not exist on type" | 型がない、または正しくない | プロパティを追加するか、インターフェースを修正する |
| "Cannot find module" | 型またはパスがない | @types をインストールするか、パスを設定する |
| "Object is possibly 'null'" | strictNullChecks が有効 | オプショナルチェーンまたは null チェックを使用する |
| "Type instantiation is excessively deep" | 複雑なジェネリックの再帰 | 型を単純化するか、型の範囲を制限する |
| "Index signature is missing" | 動的キーへのアクセス | Record を使用するか、インデックスシグネチャを追加する |
| ビルドに時間がかかりすぎる | ファイル数が多く、インクリメンタルビルドが無効 | インクリメンタルビルドを有効にし、プロジェクト参照を使用する |
静的解析とリンティング
公式ルールのリファレンス
| ツール | ルール数 | ドキュメント |
|---|---|---|
| ESLint | 200+ | https://eslint.org/docs/latest/rules/ |
| TypeScript-ESLint | 100+ | https://typescript-eslint.io/rules/ |
| Biome | 200+ | https://biomejs.dev/linter/rules/ |
| SonarJS | 422 | https://rules.sonarsource.com/javascript/ |
有効にする主要ルール
// eslint.config.js (ESLint 9+)
export default [
{
rules: {
// Prevent bugs
'no-unused-vars': 'error',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-misused-promises': 'error',
// Code quality
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
'complexity': ['warn', 10],
'max-depth': ['warn', 4],
}
}
];
推奨設定
| ツール | 設定 | コマンド |
|---|---|---|
| ESLint | @eslint/js recommended | npm init @eslint/config |
| TypeScript-ESLint | strict-type-checked | ts-eslint のドキュメントを参照 |
| Biome | デフォルト | npx @biomejs/biome init |
本番環境への準備
厳格な設定
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
エラー処理
// Type-safe error handling
class AppError extends Error {
constructor(
message: string,
public readonly code: string,
public readonly statusCode: number = 500
) {
super(message);
this.name = 'AppError';
}
}
// Result type pattern
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
async function safeAsync<T>(
promise: Promise<T>
): Promise<Result<T>> {
try {
const data = await promise;
return { success: true, data };
} catch (error) {
return { success: false, error: error as Error };
}
}
// Usage
const result = await safeAsync(fetchUser(id));
if (result.success) {
console.log(result.data);
} else {
console.error(result.error.message);
}
型安全性のパターン
// Branded types for type safety
type UserId = string & { readonly brand: unique symbol };
type OrderId = string & { readonly brand: unique symbol };
function createUserId(id: string): UserId {
return id as UserId;
}
// Exhaustive checking
function assertNever(x: never): never {
throw new Error(`Unexpected value: ${x}`);
}
type Status = 'active' | 'inactive' | 'pending';
function handleStatus(status: Status): string {
switch (status) {
case 'active': return 'Active';
case 'inactive': return 'Inactive';
case 'pending': return 'Pending';
default: return assertNever(status);
}
}
// Zod for runtime validation
import { z } from 'zod';
const UserSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(2),
});
type User = z.infer<typeof UserSchema>;
function parseUser(data: unknown): User {
return UserSchema.parse(data);
}
テスト
// Type testing with expectTypeOf
import { expectTypeOf, describe, it } from 'vitest';
describe('types', () => {
it('User has correct shape', () => {
expectTypeOf<User>().toMatchTypeOf<{
id: string;
email: string;
name: string;
}>();
});
it('createUser returns User', () => {
expectTypeOf(createUser).returns.toEqualTypeOf<User>();
});
});
// Unit testing with proper types
import { describe, it, expect, vi } from 'vitest';
describe('UserService', () => {
it('fetches user by id', async () => {
const mockUser: User = {
id: '123',
email: '[email protected]',
name: 'Test',
};
const repository = {
findById: vi.fn().mockResolvedValue(mockUser),
};
const service = new UserService(repository);
const result = await service.getUser('123');
expect(result).toEqual(mockUser);
expect(repository.findById).toHaveBeenCalledWith('123');
});
});
パフォーマンス
// Lazy initialization
class ExpensiveService {
private static instance: ExpensiveService | null = null;
static getInstance(): ExpensiveService {
if (!this.instance) {
this.instance = new ExpensiveService();
}
return this.instance;
}
}
// Memoization with proper types
function memoize<Args extends unknown[], Result>(
fn: (...args: Args) => Result
): (...args: Args) => Result {
const cache = new Map<string, Result>();
return (...args: Args): Result => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key)!;
}
const result = fn(...args);
cache.set(key, result);
return result;
};
}
監視指標
| 指標 | 目標 |
|---|---|
| 型カバレッジ | > 95% |
| any の使用 | 0 件 |
| ビルド時間 | < 30s |
| 型エラー | 0 |
チェックリスト
- strict: true を有効化
- noUncheckedIndexedAccess を有効化
- 明示的な any の使用なし
- ID にブランド型を使用
- エラー処理に Result 型を使用
- Zod によるランタイム検証
- expectTypeOf による型テスト
- 宣言ファイルを生成
- ソースマップを有効化
- typescript-eslint を使用した ESLint
リファレンスドキュメント
詳細な知識:包括的なドキュメントを参照するには、technology:
typescriptを指定してmcp__documentation__fetch_docsを使用してください。
コメント
Markdown 対応