mcpField
M
mastering-typescript

mastering-typescript

github.com/spillwavesolutions開発31795 回インストール43 週間前に更新
リポジトリ

mastering-typescript について

mastering-typescriptは、TypeScriptアプリの開発や移行に取り組む開発者向けのスキルです。最新の型システムパターン、フレームワークの例、Zodによる検証、ツールチェーン設定を、参考資料や設定ファイルとともにまとめています。

主な機能

  1. 01最新のTypeScript型システムパターン
  2. 02ジェネリクス、マップ型、条件型
  3. 03ReactとNestJSの例
  4. 04Zodスキーマ検証
  5. 05ツールチェーン設定ガイド
  6. 06移行ガイドと設定ファイル

活用シーン

  1. 01型安全なReactまたはNestJSアプリの構築
  2. 02JavaScriptコードベースの段階的な移行
  3. 03Zodを使った検証付きAPI契約の設計
  4. 04TypeScriptプロジェクトのツール設定

インストール

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

$npx skills add https://github.com/spillwavesolutions/mastering-typescript-skill --skill mastering-typescript

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/
eslint-template.js
tsconfig-template.json
references/
enterprise-patterns.md
generics.md
nestjs-integration.md
react-integration.md
toolchain.md
type-system.md
scripts/
validate-setup.sh

詳細

モダン TypeScript のマスター

TypeScript 5.9+ でエンタープライズグレードの型安全なアプリケーションを構築しましょう。

互換性: TypeScript 5.9+、Node.js 22 LTS、Vite 7、NestJS 11、React 19

クイックスタート

# Initialize TypeScript project with ESM
pnpm create vite@latest my-app --template vanilla-ts
cd my-app && pnpm install

# Configure strict TypeScript
cat > tsconfig.json << 'EOF'
{
  "compilerOptions": {
    "target": "ES2024",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}
EOF

このスキルを使うべき場面

次のような場合に使用します:

  • 型安全な React、NestJS、Node.js アプリケーションを構築する場合
  • JavaScript のコードベースを TypeScript に移行する場合
  • 高度な型パターン(ジェネリクス、マップ型、条件型)を実装する場合
  • モダンな TypeScript ツールチェーン(Vite、pnpm、ESLint)を設定する場合
  • Zod バリデーションを用いた型安全な API コントラクトを設計する場合
  • TypeScript のアプローチを Java や Python と比較する場合

プロジェクトセットアップチェックリスト

TypeScript プロジェクトを始める前に:

- [ ] Use pnpm for package management (faster, disk-efficient)
- [ ] Configure ESM-first (type: "module" in package.json)
- [ ] Enable strict mode in tsconfig.json
- [ ] Set up ESLint with @typescript-eslint
- [ ] Add Prettier for consistent formatting
- [ ] Configure Vitest for testing

型システム早見表

プリミティブ型
const name: string = "Alice";
const age: number = 30;
const active: boolean = true;
const id: bigint = 9007199254740991n;
const key: symbol = Symbol("unique");
ユニオン型とインターセクション型
// Union: value can be one of several types
type Status = "pending" | "approved" | "rejected";

// Intersection: value must satisfy all types
type Employee = Person & { employeeId: string };

// Discriminated union for type-safe handling
type Result<T> =
  | { success: true; data: T }
  | { success: false; error: string };

function handleResult<T>(result: Result<T>): T | null {
  if (result.success) {
    return result.data; // TypeScript knows data exists here
  }
  console.error(result.error);
  return null;
}
型ガード
// typeof guard
function process(value: string | number): string {
  if (typeof value === "string") {
    return value.toUpperCase();
  }
  return value.toFixed(2);
}

// Custom type guard
interface User { type: "user"; name: string }
interface Admin { type: "admin"; permissions: string[] }

function isAdmin(person: User | Admin): person is Admin {
  return person.type === "admin";
}
satisfies 演算子(TS 5.0+)

推論を保持しつつ型の適合性を検証します:

// Problem: Type assertion loses specific type info
const colors1 = {
  red: "#ff0000",
  green: "#00ff00"
} as Record<string, string>;

colors1.red.toUpperCase(); // OK, but red could be undefined

// Solution: satisfies preserves literal types
const colors2 = {
  red: "#ff0000",
  green: "#00ff00"
} satisfies Record<string, string>;

colors2.red.toUpperCase(); // OK, and TypeScript knows red exists

ジェネリクスのパターン

基本的なジェネリック関数
function first<T>(items: T[]): T | undefined {
  return items[0];
}

const num = first([1, 2, 3]);     // number | undefined
const str = first(["a", "b"]);   // string | undefined
制約付きジェネリクス
interface HasLength {
  length: number;
}

function logLength<T extends HasLength>(item: T): T {
  console.log(item.length);
  return item;
}

logLength("hello");     // OK: string has length
logLength([1, 2, 3]);   // OK: array has length
logLength(42);          // Error: number has no length
ジェネリックな API レスポンスラッパー
interface ApiResponse<T> {
  data: T;
  status: number;
  timestamp: Date;
}

async function fetchUser(id: string): Promise<ApiResponse<User>> {
  const response = await fetch(`/api/users/${id}`);
  const data = await response.json();
  return {
    data,
    status: response.status,
    timestamp: new Date()
  };
}

ユーティリティ型リファレンス

型目的例
Partial<T>すべてのプロパティを省略可能にするPartial<User>
Required<T>すべてのプロパティを必須にするRequired<Config>
Pick<T, K>特定のプロパティを選択するPick<User, "id" | "name">
Omit<T, K>特定のプロパティを除外するOmit<User, "password">
Record<K, V>キーと値の型を持つオブジェクトRecord<string, number>
ReturnType<F>関数の戻り値型を抽出するReturnType<typeof fn>
Parameters<F>関数のパラメーターを抽出するParameters<typeof fn>
Awaited<T>Promise 型をアンラップするAwaited<Promise<User>>

条件型

// Basic conditional type
type IsString<T> = T extends string ? true : false;

// Extract array element type
type ArrayElement<T> = T extends (infer E)[] ? E : never;

type Numbers = ArrayElement<number[]>; // number
type Strings = ArrayElement<string[]>; // string

// Practical: Extract Promise result type
type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;

マップ型

// Make all properties readonly
type Immutable<T> = {
  readonly [K in keyof T]: T[K];
};

// Make all properties nullable
type Nullable<T> = {
  [K in keyof T]: T[K] | null;
};

// Create getter functions for each property
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

interface Person { name: string; age: number }
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number }

フレームワークとの統合

TypeScript での React
// Typed functional component
interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: "primary" | "secondary";
}

const Button: React.FC<ButtonProps> = ({ label, onClick, variant = "primary" }) => (
  <button className={variant} onClick={onClick}>
    {label}
  </button>
);

// Typed hooks
const [count, setCount] = useState<number>(0);
const userRef = useRef<HTMLInputElement>(null);
TypeScript での NestJS
// Type-safe DTO with class-validator
import { IsString, IsEmail, MinLength } from 'class-validator';

class CreateUserDto {
  @IsString()
  @MinLength(2)
  name: string;

  @IsEmail()
  email: string;
}

// Or with Zod (modern approach)
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(2),
  email: z.string().email()
});

type CreateUserDto = z.infer<typeof CreateUserSchema>;

詳細なパターンについては react-integration.md と nestjs-integration.md を参照してください。

Zod によるバリデーション

import { z } from 'zod';

// Define schema
const UserSchema = z.object({
  id: z.string().uuid(),
  name: z.string().min(1).max(100),
  email: z.string().email(),
  role: z.enum(["user", "admin", "moderator"]),
  createdAt: z.coerce.date()
});

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

// Validate at runtime
function parseUser(data: unknown): User {
  return UserSchema.parse(data); // Throws ZodError if invalid
}

// Safe parsing (returns result object)
const result = UserSchema.safeParse(data);
if (result.success) {
  console.log(result.data); // Typed as User
} else {
  console.error(result.error.issues);
}

モダンなツールチェーン(2025)

ツールバージョン目的
TypeScript5.9+型チェックとコンパイル
Node.js22 LTSランタイム環境
Vite7.xビルドツールおよび開発サーバー
pnpm9.xパッケージマネージャー
ESLint9.xflat config によるリンティング
Vitest3.xテストフレームワーク
Prettier3.xコードフォーマット
ESLint の Flat Config(ESLint 9+)
// eslint.config.js
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';

export default tseslint.config(
  eslint.configs.recommended,
  ...tseslint.configs.strictTypeChecked,
  {
    languageOptions: {
      parserOptions: {
        projectService: true,
        tsconfigRootDir: import.meta.dirname,
      },
    },
  }
);

移行戦略

段階的な移行
  1. tsconfig.json に allowJs: true と checkJs: false を追加する
  2. ファイルを一度に 1 つずつ .js から .ts にリネームする
  3. 型注釈を徐々に追加する
  4. より厳格なオプションを段階的に有効にする
段階的な型付けのための JSDoc
// Before full migration, use JSDoc
/**
 * @param {string} name
 * @param {number} age
 * @returns {User}
 */
function createUser(name, age) {
  return { name, age };
}

包括的な移行ガイドについては enterprise-patterns.md を参照してください。

よくある間違い

間違い問題修正方法
any を多用する型安全性が損なわれるunknown を使用して絞り込む
strict モードを無視するnull/undefined のバグを見逃すすべての strict オプションを有効にする
型アサーション(as)型エラーを隠してしまう可能性があるsatisfies または型ガードを使用する
単純なユニオンに enum を使うランタイムコードが生成される代わりにリテラルユニオンを使用する
API データを検証しないランタイムの型の不一致境界で Zod を使用する

言語間の比較

機能TypeScriptJavaPython
型システム構造的名前的段階的(ダックタイピング)
Null 許容性明示的(T | null)@Nullable アノテーションtyping による Optional
ジェネリクス型レベル、消去される型レベル、消去されるtyping によるランタイム
インターフェース構造的マッチング実装が必須プロトコル(3.8+)
Enum避ける(ユニオンを使用)第一級Enum クラス

参照ファイル

アセット

スクリプト

コメント