dev.syw

제네릭 함수·인터페이스·클래스와 제약(extends), 기본 타입 매개변수로 재사용 가능한 타입을 만든다.

제네릭

제네릭(generic)은 타입을 매개변수처럼 다루는 기능입니다. 어떤 타입에도 동작하면서, 들어온 타입 정보를 그대로 유지하는 재사용 가능한 코드를 만들 수 있습니다.

학습 목표

  • 제네릭 함수를 작성한다.
  • 제네릭 인터페이스와 클래스를 만든다.
  • extends 로 타입 제약을 건다.
  • 기본 타입 매개변수를 지정한다.

왜 제네릭인가

타입을 고정하면 재사용이 안 되고, any 를 쓰면 타입 정보를 잃습니다.

function firstAny(arr: any[]): any {
  return arr[0];
}

const x = firstAny([1, 2, 3]); // x는 any → number라는 정보 사라짐

제네릭은 "들어온 타입을 그대로 돌려준다"를 표현합니다.

function first<T>(arr: T[]): T {
  return arr[0];
}

const n = first([1, 2, 3]);     // number
const s = first(['a', 'b']);    // string

<T> 는 타입 자리표(placeholder)이고, 호출 시점에 실제 타입으로 채워집니다. 보통은 인자에서 자동으로 추론됩니다.

여러 타입 매개변수

필요하면 여러 개를 받을 수 있습니다.

function pair<K, V>(key: K, value: V): [K, V] {
  return [key, value];
}

const p = pair('age', 20); // [string, number]

제네릭 인터페이스

인터페이스에도 타입 매개변수를 줄 수 있습니다.

interface ApiResponse<T> {
  ok: boolean;
  data: T;
}

const userRes: ApiResponse<{ name: string }> = {
  ok: true,
  data: { name: '민수' },
};

제네릭 클래스

클래스도 마찬가지로 타입을 매개변수화합니다.

class Box<T> {
  constructor(private value: T) {}

  get(): T {
    return this.value;
  }
}

const numBox = new Box(123);   // Box<number>
numBox.get();                  // number

타입 제약 — extends

"아무 타입"이면 곤란할 때가 있습니다. extends 로 "최소한 이런 모양이어야 한다"는 제약을 겁니다.

function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}

longest('apple', 'kiwi');     // OK (문자열엔 length가 있음)
longest([1, 2], [1, 2, 3]);   // OK (배열에도 length)
longest(10, 20);              // ❌ number엔 length가 없음

💡 TIP — 제약을 걸면 함수 안에서 그 속성(a.length)을 안전하게 쓸 수 있습니다. 제약 없는 T 에서는 .length 접근이 막힙니다.

keyof 와 함께 쓰기

객체의 키만 받도록 제약하는 흔한 패턴입니다.

function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: '민수', age: 20 };
getProp(user, 'name'); // string
getProp(user, 'xyz');  // ❌ 'xyz'는 user의 키가 아님

기본 타입 매개변수

= 타입 으로 기본값을 지정하면, 명시하지 않았을 때 그 타입이 쓰입니다.

interface Container<T = string> {
  value: T;
}

const a: Container = { value: 'hi' };     // T = string
const b: Container<number> = { value: 1 }; // T = number

요약

  • <T> 로 타입을 매개변수화해 재사용성과 타입 안전성을 동시에 얻는다.
  • 함수·인터페이스·클래스 모두 제네릭을 쓸 수 있다.
  • extends 로 타입에 제약을 걸어 특정 속성 사용을 보장한다.
  • K extends keyof T 는 객체 키를 안전하게 다루는 핵심 패턴.
  • = 타입 으로 기본 타입 매개변수를 지정할 수 있다.

댓글 0

TypeScript” 강좌에 대한 댓글입니다.

댓글을 작성하려면 로그인이 필요합니다.