실무에서 자주 쓰는 제네릭 패턴을 작업별로 묶었습니다. 타입 매개변수 선언, 제약 걸기, 기본값 지정, 조건부 타입으로 분기, infer로 추출, 형태 매핑. 각 행은 패턴과 한 줄 예제를 짝지어 보여줍니다.
제네릭은 타입 매개변수입니다. 호출자가 선택할 타입의 자리표시자로, 하나의 함수나 타입이 정밀도를 잃지 않으면서 여러 형태에 동작하게 합니다. <T>는 '어떤 타입 T에 대해'로 읽으세요. 힘은 T를 제약하고, 분기하고, 매핑하는 데서 나옵니다. 아래 패턴이 실무 어휘입니다.
참고 표 · 28 항목
TypeScript 제네릭Explained
28 of 28 rows
선언
호출자가 선택하는 타입 매개변수.
function first<T>(xs: T[]): T
여러 개의 독립적인 타입 매개변수.
function pair<T, U>(a: T, b: U): [T, U]
첫 번째 것의 키에 묶인 두 번째 매개변수.
function get<T, K extends keyof T>(o: T, k: K): T[K]
필드와 메서드에 타입 매개변수를 갖는 클래스.
class Box<T> { value: T }
타입 매개변수를 갖는 객체 형태.
interface Result<T> { data: T }
화살표 함수의 타입 매개변수. 끝의 쉼표는 .tsx 파일이 JSX로 해석하는 것을 막습니다.
const first = <T,>(xs: T[]): T => xs[0]
제약
T가 Type에 할당 가능하도록 요구합니다.
function len<T extends { length: number }>(x: T)
T를 다른 타입의 키로 제한합니다.
type Keys<O> = keyof O
T를 new로 생성 가능한 클래스로 제한합니다.
function make<C extends new () => C>(c: C): C
T가 여러 제약을 동시에 만족하도록 요구합니다.
function log<T extends Error & { code: number }>(e: T)
무엇으로든 제한합니다. 매개변수를 좁히지 않고 제네릭으로 유지합니다.
type Wrap<T> = T extends unknown ? { v: T } : never
기본값과 infer
호출자가 생략할 때 T에 기본값을 지정합니다.
function parse<T = string>(): T
조건부 타입 안에서 타입을 추출합니다.
type El<T> = T extends Array<infer I> ? I : never
중첩된 Promise를 내부 타입까지 풀어냅니다.
type Data = Awaited<Promise<User>>
템플릿 리터럴 타입의 한 조각을 추출합니다.
type Path<S> = S extends `/api/${infer R}` ? R : never
유니언 전체를 한 번에 검사합니다. 네이키드 T는 한 번에 한 멤버씩 추론합니다.
type El<T> = [T] extends [Array<infer I>] ? I : never
조건부와 매핑
T가 U에 할당 가능한지에 따라 타입을 고릅니다.
type IsStr<T> = T extends string ? true : false
T의 각 키를 변환해 새 객체 타입을 만듭니다.
type Frozen<T> = { [K in keyof T]: Readonly<T[K]> }
키가 K이고 값이 V인 객체.
type Scores = Record<string, number>
위 패턴에서 파생된 내장 제네릭.
type Preview = Pick<User, "id" | "name">
extends 앞의 네이키드 T는 유니언 멤버마다 한 번씩 실행되어 결과를 유니언으로 합칩니다.
ToArray<'a' | 'b'> = 'a'[] | 'b'[]
매핑된 키에 수식자를 추가하거나 제거합니다.
type Req<T> = { [K in keyof T]-?: T[K] }
런타임 값의 키를 타입으로 가져옵니다.
const opts = { a: 1 }; type K = keyof typeof opts
다른 문자열 타입으로부터 문자열 타입을 만듭니다.
type Route = `/users/${string}`
튜플 타입을 끝에서 끝까지 이어 붙입니다.
type Concat<T extends unknown[], U extends unknown[]> = [...T, ...U]
정의가 자기 자신을 참조하는 타입.
type Json = string | number | Json[] | { [k: string]: Json }
값을 타입에 대해 검사하고 더 좁은 리터럴 타입을 유지합니다.
const c = { dark: "#000" } satisfies Record<string, string>