삼태연구소
SAMTAELABS삼태연구소
가이드2026년 4월 14일·7분 읽기

외주 개발에서 타입스크립트 제네릭을 써야 하는 이유

타입스크립트제네릭외주개발IT에이전시프론트엔드개발코드품질API타입설계유지보수
외주 개발에서 타입스크립트 제네릭을 써야 하는 이유

한줄 요약

타입 안전성을 포기하지 않으면서 코드 중복을 없애는 방법이 제네릭이다.

외주 프로젝트에서 타입스크립트 제네릭이 왜 문제가 되나

타입스크립트 제네릭은 외주 개발 현장에서 유독 자주 문제가 된다. 읽는 건 어떻게든 되는데, 직접 설계하려면 손이 멈추는 경우가 많다. 에이전시에서는 이 문제가 단순한 개인기량 차원을 넘어선다. 개발자마다 제네릭을 쓰는 방식이 제각각이면 코드베이스가 예측 불가능해지고, 이후 유지보수 단계에서 클라이언트가 이탈할 근거가 된다.

제네릭을 제대로 이해하려면, 제네릭이 없을 때 어떤 일이 벌어지는지부터 봐야 한다.

타입 하드코딩이 외주 코드베이스를 망치는 방식

API 연동이 핵심인 외주 프로젝트에서 흔한 패턴이 있다. 엔드포인트마다 응답 타입을 별도로 정의하는 것이다. 회원 API 응답 타입, 상품 API 응답 타입, 주문 API 응답 타입을 따로따로 만든다. 구조는 완전히 같은데, 데이터 부분의 타입만 다르다.

interface UserApiResponse {
  success: boolean;
  statusCode: number;
  data: User;
  message: string;
}

interface ProductApiResponse {
  success: boolean;
  statusCode: number;
  data: Product;
  message: string;
}

엔드포인트가 10개면 이 인터페이스가 10개다. 응답 구조가 바뀌면 10군데를 전부 수정해야 한다. 누군가 하나를 빠뜨리면 그게 버그가 된다. 외주 프로젝트는 일정이 촘촘하기 때문에, 이런 코드는 납품 이후 유지보수 단계에서 터진다.

any로 때우는 방식은 더 나쁘다. 타입 정보가 사라지면 IDE 자동완성도 사라지고, 런타임 에러가 발생하기 전까지 아무도 문제를 모른다. 타입스크립트를 쓰는 의미가 없어진다.


제네릭으로 API 응답 구조를 한 번만 정의하는 방법

제네릭은 타입을 매개변수처럼 받는다. 함수가 값을 매개변수로 받듯, 제네릭은 타입을 매개변수로 받는다. 구조는 고정하고, 달라지는 부분만 열어두는 방식이다.

interface ApiResponse<T> {
  success: boolean;
  statusCode: number;
  data: T;
  message: string;
}

type UserResponse = ApiResponse<User>;
type ProductListResponse = ApiResponse<Product[]>;

인터페이스 하나로 모든 API 응답을 커버한다. 응답 구조가 바뀌면 한 곳만 고치면 된다. 프로젝트 규모가 클수록, 엔드포인트가 많을수록 이 차이는 커진다.

함수에서도 동일한 원리가 적용된다. 타입 매개변수 T를 함수 선언부에 붙이면, 호출 시점에 전달하는 값을 보고 타입스크립트가 T를 알아서 추론한다.

function extractField<T, K extends keyof T>(items: T[], field: K): T[K][] {
  return items.map((item) => item[field]);
}

K extends keyof TK가 반드시 T의 실제 키여야 한다는 제약이다. 존재하지 않는 필드명을 넘기면 컴파일 단계에서 잡힌다. 런타임이 아니라 개발 중에.

에이전시에서 제네릭 설계가 곧 유지보수 비용이다

외주 개발의 특성상, 코드를 처음 짜는 사람과 나중에 고치는 사람이 다른 경우가 많다. 클라이언트가 직접 내부 개발팀을 구성하거나, 다른 에이전시로 전환하거나, 우리가 다시 투입되거나. 어떤 경우든 코드가 자기 설명을 해야 한다.

잘 설계된 제네릭 타입은 코드 자체가 문서가 된다. ApiResponse<User>를 보면 이게 유저 데이터를 담은 API 응답이라는 걸 한눈에 알 수 있다. 반면 any가 산발적으로 뿌려진 코드는 무엇을 넘기는지, 무엇이 돌아오는지 실행해보기 전까지 알 수 없다.

유틸리티 함수 설계에서도 마찬가지다. 배열 필터링, 페이지네이션 처리, 로컬 스토리지 래퍼처럼 공통으로 쓰이는 함수에 제네릭을 적용하면, 새로운 데이터 타입이 생겨도 함수를 새로 만들 필요가 없다. 팀 규모가 작은 에이전시일수록 이 생산성 차이가 직접적으로 납기일에 영향을 준다.

제네릭 도입 시점과 도입 방식

모든 코드에 제네릭을 붙이는 게 목표가 아니다. 과도한 추상화는 오히려 코드를 읽기 어렵게 만든다. 에이전시 실무에서 제네릭을 쓸 타이밍은 명확하다.

첫째, 구조는 같은데 타입만 다른 패턴이 반복될 때. 둘째, 여러 타입에 동일한 로직을 적용하는 유틸 함수를 만들 때. 셋째, 라이브러리나 공통 모듈처럼 다수의 팀원이 공유해서 쓰는 코드를 설계할 때.

반대로, 특정 타입 하나에만 쓰이는 단순한 함수에 억지로 제네릭을 끼워 넣는 건 오버엔지니어링이다. 코드 리뷰 비용만 늘어난다.

타입스크립트가 제공하는 Partial, Pick, Omit, ReturnType 같은 유틸리티 타입도 전부 제네릭으로 만들어져 있다. 제네릭에 익숙해지면 이 유틸리티 타입들을 조합해서 쓰는 것도 자연스러워지고, 결과적으로 타입 정의 작업 자체의 속도가 올라간다.

자주 묻는 질문

Q.외주 프로젝트에서 `any`를 쓰면 왜 문제가 되나요?

`any`는 타입스크립트의 타입 검사를 통째로 우회한다. 컴파일 단계에서 잡혀야 할 오류가 런타임으로 미뤄지고, 납품 이후 클라이언트 서비스 운영 중에 터진다. 유지보수 계약이 없는 상황이라면 에이전시 신뢰도 문제로 이어진다. `any`는 임시방편으로 쓰더라도 기술 부채로 기록해두고 반드시 해소해야 한다.

Q.제네릭을 처음 쓰는 주니어 개발자가 팀에 있을 때 어떻게 온보딩해야 하나요?

추상적인 문법 설명보다 실제 프로젝트의 API 응답 타입처럼 구체적인 사례에서 출발하는 게 효과적이다. 이미 작성된 제네릭 코드를 읽고 동작 원리를 파악하는 연습을 먼저 하고, 이후 유틸 함수 한두 개를 직접 제네릭으로 바꿔보는 실습으로 이어가는 방식이 현장에서 잘 맞는다. 팀 코드 컨벤션에 제네릭 사용 가이드라인을 짧게라도 문서화해두면 온보딩 속도가 빠르다.

Q.제네릭을 남발하면 어떤 부작용이 생기나요?

타입 매개변수가 3개 이상 중첩되기 시작하면 코드를 읽는 데 드는 인지 비용이 급격히 올라간다. 특히 에이전시처럼 인력이 교체되는 환경에서는 과도하게 추상화된 제네릭이 오히려 유지보수를 어렵게 만든다. 반복 패턴이 명확할 때만 제네릭을 적용하고, 단일 타입에만 쓰이는 코드에는 굳이 제네릭을 도입하지 않는 것이 실무적으로 올바른 판단이다.

직접 구축이 어렵다면, 전문가에게 맡겨보세요

대표 개발자가 직접 소통하고, 설계하고, 구축합니다. 중간 과정 없이 의도 그대로.

다른 아티클