본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

타입스크립트 제네릭

avatar
yceffort
2019-09-20 · 4분
4min
2019year
KOoriginal
typescript

제네릭이란

제네릭은 클래스 내부에서 사용하는 데이터의 타입을 외부에서 지정하는 것을 의미한다. 어떤 타입의 데이터를 쓸지를, 클래스 선언부가 아니라 외부에서 결정하는 것이다. 일단 자바 코드로 한번 살펴보자.

class Person<T>{
    public T name;
}

Person<String> p1 = new Person<String>();
Person<StringBuilder> p1 = new Person<StringBuilder>();

T라는 데이터 타입은 존재하지 않는다. T는 name의 타입으로, 아래 처럼 Person을 사용하는 곳에서 정해진다. 따라서 string이 될수도, stringbuilder가 될수도 있는 것이다.

하지만 자바스크립트에서는 제네릭을 쓸일이 없다. 타입이 없기 때문에, 타입에 맞지 않는 코딩을 한다면 런타임에서 에러가 발생한다. 하지만 타입스크립트는 정적타입 언어이기 때문에 제네릭이 필요하게 되었다.

any를 그냥 쓰면 안되나?

아래 코드를 살펴보자.

class School {
  private students: any[] = []

  constructor() {}

  go(student: any): void {
    this.students.push(student)
  }

  bye(): void {
    this.students.pop()
  }
}
const school = new School()
stack.push('라이오넬 멧시')
stack.push(10)
stack.pop().substring(0)
stack.pop().substring(0) // 에러

string에 이어서 number도 일일이 대응하기 위해서는 any를 쓰거나, 상속을 받아야 할 것이다.

typescript 문법

class School<T> {
  private students: T[] = []

  constructor() {}

  go(student: T): void {
    this.students.push(student)
  }

  bye(): T {
    return this.students.pop()
  }
}

<T>는 제네릭을 의미하며, 그안에 타입으로 사용될 T를 넣었다. 다른 문자도 되지만, 대게는 T를 쓰고 Type Variables라고 한다.

const numberSchool = new School<number>()
const stringSchool = new School<string>()
const stringSchool = new School<boolean>()

이제 각각의 타입이 선언되어 사용될 수 가 있다.

함수에 써보기

다양한 타입의 array를 받아서 그 array의 첫번째를 리턴하는 함수를 만든다고 가정해보자. any를 사용한다면

function returnFirstItem(items: any[]): any {
  return items[0]
}

하지만 제네릭을 쓴다면

function returnFirstItem<T>(items: T[]): T {
  return items[0]
}

returnFirstItem < number > [0, 1, 2, 3]

이 된다.

여러개 Generic

function multipleGeneric<T, U>(a1: T, a2: U): [T, U] {
  return [a1, a2]
}

multipleGeneric<string, boolean>('true', true)

rest에서 제네릭

interface XYZ {
  x: any
  y: any
  z: any
}

function dropXYZ<T extends XYZ>(obj: T) {
  let {x, y, z, ...rest} = obj
  return rest
}

객체에서 x, y, z를 빼다가 나머지를 리턴하는 함수이다. 객체에서 x, y, z가 없다면 컴파일 단계에서 에러가 날 것이고, x, y, z 가 있다면 어떤 타입이든 상관없이 x, y, z를 제거하고 리턴해줄 것이다.

만약 x, y, z가 없는 리턴타입까지 정확하게 명사히고 싶다면 이런 짓도 가능하다.

interface XYZ {
  x: any
  y: any
  z: any
}

// Pick<T, a>는 T에서 a만 받는 다는 것이다
// Exclude<keyof T, keyof XYZ>는 앞에 타입에서 뒤에 있는 타입을 제외해준다.
type DropXYZ<T> = Pick<T, Exclude<keyof T, keyof XYZ>>

function dropXYZ<T extends XYZ>(obj: T): DropXYZ<T> {
  let {x, y, z, ...rest} = obj
  return rest
}

conditional types에 대해서도 알아봐야 겠다.

관련 글

  • #typescript#oxc#eslint

    typescript@7을 설치하면 벌어지는 일들: 블로그 모노레포 마이그레이션 기록

    pnpm lint가 12분 32초 걸리던 모노레포에 typescript 7.0.2를 넣어봤다. 타입체크는 조용히 지나갔는데 next build가 깨졌고, lint는 크래시했다. eslint와 prettier를 oxlint와 oxfmt로 갈아탄 하루의 연쇄 반응과 전후 실측 기록. 미리 말해두면, 빌드는 빨라지지 않았다.

    2026-08-10·17분
  • #typescript#backend

    Effect 시스템 심층 분석: 모나드에서 Algebraic Effects까지, 그리고 Effect-TS의 선택

    Effect-TS가 대체 뭔데 다들 난리인지 직접 파헤쳐봤다.

    2026-02-20·41분
  • #typescript

    TypeScript에서 switch문의 모든 케이스를 빠짐없이 처리했는지 검사하는 방법

    never 타입을 활용한 exhaustive check 패턴

    2026-01-17·13분
  • #react#typescript

    useEvent에서 useEffectEvent까지: React의 이벤트 핸들러 안정화 여정

    3년 전 RFC가 드디어 빛을 보다

    2025-12-15·24분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →