Tips & Tricks

TypeScript: Claude Code 활용 가이드

typescript: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.

ジェネリクスをClaude Code로自在に操る

TypeScriptのジェネリクスは、再利用性の高い타입安全なコードを書くための強力な仕組みです。Claude Code는 ジェネリクスのパターンを深く理解しており、적절한타입매개변수の설계から複雑な制約の記述まで的確にサポートしてくれます。

기본적인ジェネリック함수の생성

まずはClaude Code에シンプルなジェネリック함수を생성してもらいましょう。

> 배열から重複を除去するジェネリック함수를 생성해줘。
> 객체배열にも대응し、キーを指定できるようにして。
function uniqueBy<T, K extends keyof T>(array: T[], key?: K): T[] {
  if (!key) {
    return [...new Set(array)];
  }
  const seen = new Map<T[K], T>();
  for (const item of array) {
    const value = item[key];
    if (!seen.has(value)) {
      seen.set(value, item);
    }
  }
  return [...seen.values()];
}

// Usage example
const users = [
  { id: 1, name: "Alice" },
  { id: 2, name: "Bob" },
  { id: 1, name: "Alice (duplicate)" },
];

const unique = uniqueBy(users, "id");
// => [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]

K extends keyof T という制約により、存在しない프로퍼티を指定すると컴파일時に에러になります。

条件타입를 사용한高度なパターン

Claude Code는 条件타입(Conditional Types)も的確に생성します。

> API응답の타입を、성공時と에러時で分岐するジェネリック타입を作って。
> ステータスコードに応じて타입が変わるようにして。
type ApiResult<T, E = Error> =
  | { status: "success"; data: T; error: never }
  | { status: "error"; data: never; error: E };

type ExtractData<R> = R extends { status: "success"; data: infer D } ? D : never;
type ExtractError<R> = R extends { status: "error"; error: infer E } ? E : never;

// 응답핸들러ー
function handleResponse<T>(result: ApiResult<T>): T {
  if (result.status === "success") {
    return result.data; // 타입が T に絞り込まれる
  }
  throw result.error;
}

// Usage example
interface User {
  id: string;
  name: string;
}

const result: ApiResult<User> = await fetchUser("123");
const user = handleResponse(result); // 타입は User

ジェネリック클래스でリポジトリパターン

데이터アクセス層をジェネリクスで抽象化するパターンも、Claude Code에任せると효율적입니다。

interface Entity {
  id: string;
  createdAt: Date;
  updatedAt: Date;
}

interface Repository<T extends Entity> {
  findById(id: string): Promise<T | null>;
  findMany(filter: Partial<T>): Promise<T[]>;
  create(data: Omit<T, "id" | "createdAt" | "updatedAt">): Promise<T>;
  update(id: string, data: Partial<Omit<T, "id">>): Promise<T>;
  delete(id: string): Promise<void>;
}

class PrismaRepository<T extends Entity> implements Repository<T> {
  constructor(private model: any) {}

  async findById(id: string): Promise<T | null> {
    return this.model.findUnique({ where: { id } });
  }

  async findMany(filter: Partial<T>): Promise<T[]> {
    return this.model.findMany({ where: filter });
  }

  async create(data: Omit<T, "id" | "createdAt" | "updatedAt">): Promise<T> {
    return this.model.create({ data });
  }

  async update(id: string, data: Partial<Omit<T, "id">>): Promise<T> {
    return this.model.update({ where: { id }, data });
  }

  async delete(id: string): Promise<void> {
    await this.model.delete({ where: { id } });
  }
}

ジェネリクスの制約を활용したビルダーパターン

타입매개변수の制約を組み合わせた타입安全なビルダーも생성할 수 있습니다。

type QueryBuilder<T extends Record<string, unknown>> = {
  where<K extends keyof T>(key: K, value: T[K]): QueryBuilder<T>;
  orderBy<K extends keyof T>(key: K, direction: "asc" | "desc"): QueryBuilder<T>;
  select<K extends keyof T>(...keys: K[]): QueryBuilder<Pick<T, K>>;
  execute(): Promise<T[]>;
};

function createQuery<T extends Record<string, unknown>>(
  table: string
): QueryBuilder<T> {
  const conditions: string[] = [];
  const orders: string[] = [];
  let selectedFields: string[] = [];

  const builder: QueryBuilder<T> = {
    where(key, value) {
      conditions.push(`${String(key)} = '${value}'`);
      return builder as any;
    },
    orderBy(key, direction) {
      orders.push(`${String(key)} ${direction}`);
      return builder;
    },
    select(...keys) {
      selectedFields = keys.map(String);
      return builder as any;
    },
    async execute() {
      // 実際の쿼리実行ロジック
      return [];
    },
  };

  return builder;
}

Claude Codeへの효과적인プロンプト

ジェネリクスをClaude Code에依頼する際のコツをまとめます。

  1. 구체적인使用例を示す - 「こ와 같은入출력になる함수」と伝える
  2. 制約を明示する - 「TはRecord타입に限定」など타입制約を指定する
  3. ユースケースを複数提示する - 多様な使い方を示すと精度が上がる
> ジェネリック타입 DeepPartial<T> を作って。
> ネストした객체の모든프로퍼티をオプショナルにする。
> 배열の要素もDeepPartialにして。
type DeepPartial<T> = T extends (infer U)[]
  ? DeepPartial<U>[]
  : T extends object
    ? { [K in keyof T]?: DeepPartial<T[K]> }
    : T;

정리

Claude Code는 ジェネリクスの생성と최적화に非常に強力です。타입매개변수の설계、制約の付与、条件타입の활용など、複雑なパターンもプロンプト一つで구현할 수 있습니다。

TypeScriptの타입활용を더 나아가深めたい方はTypeScript개발を加速する実践Tipsを、ユーティリティ타입の応用はユーティリティ타입활용가이드를 참고하세요.또한、TypeScript公式ハンドブックのジェネリクスも併せて확인すると理解が深まります。

#Claude Code #TypeScript #generics #type safety #design patterns