Ch.15 TypeScript 기초 — AI가 이해하는 타입

제네릭과 유틸리티 타입

제네릭의 개념과 문법을 이해한다주요 유틸리티 타입(Partial, Pick, Omit, Record)을 활용할 수 있다React 컴포넌트에서 제네릭을 사용할 수 있다

같은 함수를 숫자용, 문자용 따로 만들어야 하나?

배열에서 첫 번째 요소를 꺼내는 함수를 만들었습니다. 숫자 배열용, 문자 배열용 따로 만들어야 할까요?

타입만 다른 함수를 하나로 합칠 수 없을까?

제네릭 — 타입을 변수처럼 사용해서, 하나의 함수로 모든 타입을 처리합니다.


article

핵심 내용

제네릭 = 타입의 변수 <T>로 나중에 결정할 타입을 넣습니다

// 이미 쓰고 있던 제네릭들
const nums: Array<number> = [1, 2, 3];

const p: Promise<string> = fetch("/api")
  .then(res => res.text());

const map: Map<string, number> = new Map();
map.set("score", 100);

<T>는 관례적 이름 T = Type, K = Key, V = Value, E = Element 아무 이름이나 쓸 수 있지만, 관례를 따르면 읽기 쉽습니다.

TypeScript가 기본 제공하는 유틸리티 타입으로 타입을 변환합니다

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

// Partial<T> — 모든 필드를 선택적으로
type UpdateUser = Partial<User>;
// { id?: number; name?: string; ... }

// Pick<T, K> — 특정 필드만 선택
type UserName = Pick<User, "name" | "email">;
// { name: string; email: string }

// Omit<T, K> — 특정 필드 제외
type CreateUser = Omit<User, "id">;
// { name: string; email: string; age: number }
// Record<K, V> — 키-값 매핑
type Scores = Record<string, number>;

const scores: Scores = {
  math: 90,
  english: 85,
  science: 92,
};

// 실전: 상태 관리
type LoadingState = Record<
  "users" | "posts" | "comments",
  boolean
>;

React 컴포넌트에서도 제네릭을 활용할 수 있습니다

// 제네릭 리스트 컴포넌트
interface ListProps<T> {
  items: T[];
  renderItem: (item: T) => React.ReactNode;
}

function List<T>({ items, renderItem }: ListProps<T>) {
  return (
    <ul>
      {items.map((item, i) => (
        <li key={i}>{renderItem(item)}</li>
      ))}
    </ul>
  );
}
// 사용 — 타입 자동 추론!
interface Product {
  id: number;
  name: string;
  price: number;
}

<List
  items={products}  // Product[]
  renderItem={(item) => (
    // item은 자동으로 Product 타입!
    <span>{item.name} — {item.price}원</span>
  )}
/>
// API 응답 래핑 패턴
interface ApiResponse<T> {
  data: T;
  error: string | null;
  loading: boolean;
}

// 재사용 가능한 fetch 훅
function useApi<T>(url: string): ApiResponse<T> {
  // ... 구현
}

// 사용
const { data, error } = useApi<Product[]>("/api/products");
// data는 Product[] 타입!

바이브 코더 팁: AI에게 제네릭 컴포넌트를 요청할 때 "어떤 타입이든 받을 수 있는 리스트 컴포넌트"라고 하면 제네릭을 활용한 유연한 코드를 생성해줍니다.

React에서 TypeScript를 쓰면 Props, 이벤트, 상태까지 타입으로 안전하게 관리됩니다

// Props 타입 정의
interface ButtonProps {
  label: string;
  variant?: "primary" | "secondary";
  onClick: () => void;
  disabled?: boolean;
}

function Button({ label, variant = "primary", onClick, disabled }: ButtonProps) {
  return (
    <button className={variant} onClick={onClick} disabled={disabled}>
      {label}
    </button>
  );
}
// 이벤트 타입
function SearchInput() {
  const [query, setQuery] = useState<string>("");

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setQuery(e.target.value);
  };

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    console.log("검색:", query);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input value={query} onChange={handleChange} />
    </form>
  );
}

바이브 코더 팁: AI에게 React 코드를 만들어달라고 할 때 "TypeScript로 Props 타입도 같이 만들어줘"라고 하면 자동완성과 에러 체크가 되는 안전한 코드를 받을 수 있습니다.

`Partial<User>`의 결과는?

`function first<T>(arr: T[]): T`에서 T는 함수 호출 시 자동으로 추론된다.

`Omit<User, "id" | "age">`의 결과로 남는 필드는? (User = {id, name, email, age})

Record<string, number>는 모든 키가 string이고 모든 값이 number인 객체를 뜻한다.

key

핵심 용어

🔧

Partial<T>

모든 필드를 선택적(?)으로 만듦 — 수정 폼에 유용

✂️

Pick<T, K>

지정한 필드만 골라서 새 타입 생성

🚫

Omit<T, K>

지정한 필드를 제외한 새 타입 생성

📋

Record<K, V>

키-값 형태의 객체 타입 생성

✏️

React.ChangeEvent<HTMLInputElement>

input 값 변경

📤

React.FormEvent<HTMLFormElement>

폼 제출

🖱️

React.MouseEvent<HTMLButtonElement>

버튼 클릭

⌨️

React.KeyboardEvent<HTMLInputElement>

키보드 입력

edit_note

정리 노트

제네릭과 유틸리티 타입 총정리

핵심 개념

제네릭 <T>
타입을 매개변수로 받아 재사용 가능한 코드 작성
Partial<T>
모든 속성을 선택적(optional)으로 변환
Pick<T, K>
특정 속성만 골라서 새 타입 생성
Record<K, V>
키 타입 K, 값 타입 V인 객체 타입 생성

유틸리티 타입은 기존 타입을 변환할 때 코드 중복을 줄여줍니다.

퀴즈와 인터랙션으로 더 깊이 학습하세요

play_circle인터랙티브 레슨 시작