우당탕탕

TypeScript 제네릭 타입 추론할 때 제가 헷갈렸던 체크리스트 본문

언어/JavaScript

TypeScript 제네릭 타입 추론할 때 제가 헷갈렸던 체크리스트

모찌모찝 2026. 9. 15. 18:58

TypeScript 제네릭 타입을 구현하다 보니, 생각보다 꽤 헷갈리더라고요. 특히 타입 추론이 제대로 안 될 때 뭐가 문제인지 감을 잡기 힘들었어요. 저도 처음에는 "내 코드가 왜 에러가 나는 거지?" 하면서 한참 삽질했죠.

그래서 이 글에선 제가 직접 겪으면서 꼭 확인했던 핵심 포인트들을 따로 정리해봤습니다. 이걸 체크리스트 형태로 정리해두면 막혔던 부분에서 헤매지 않고 한눈에 문제를 파악할 수 있을 거예요.

개발 환경 / 버전 정보

제가 쓰는 환경은 TypeScript 5.1, React 18 기반이에요. 물론 이 체크리스트는 기본적으로 TS 4.x 이상에서 원활히 적용되겠지만, 최신 버전일수록 타입 추론 기능이 더 안정적이라는 점 참고하세요.

TypeScript 제네릭 타입 추론 헷갈렸던 부분 정리 관련 이미지

TypeScript 제네릭 타입 추론 헷갈렸던 부분 정리 관련 정보

제네릭 타입 추론, 이렇게 하면 됩니다 ✅ 체크리스트로 꼭 확인하세요!

사실 이 부분이 제일 헷갈리더라고요. "제네릭인데 타입 추론 안 될 때", "이게 왜 any가 되지?" 이런 의문들 말이죠. 그래서 제가 직접 코딩하면서 중요하게 본 포인트를 그대로 공개할게요.

  • 함수 매개변수의 위치와 타입 선언 – 타입 추론은 주로 함수 매개변수에서 이뤄지기 때문에, 제네릭이 매개변수로 정확히 전달되는지 꼭 확인하세요. 매개변수 앞뒤에 타입을 넣으면 추론이 막힐 수 있어요.
  • 타입 기본값 (Default Type) 사용 여부 – 제네릭에 기본 타입을 넣어두면, 명시하지 않아도 일정 부분 추론이 쉬워집니다. 특히 복잡한 유틸리티 타입 쓸 때 염두에 둬야 해요.
  • 객체 타입 프로퍼티를 제네릭으로 받을 땐 – 객체 내 프로퍼티 하나하나를 타입으로 추론하려면 keyof나 조건부 타입을 함께 쓰는 게 안전합니다.
  • 호출 시 명시적 타입 인자 여부 – 타입스크립트가 자동으로 추론 못 할 때, 직접 타입 인자를 넘기는 것도 좋은 방법입니다. 무작정 추론에만 의존하지 마세요.
  • 함수 반환 타입을 제네릭으로 지정한 경우 – 반환 타입이 너무 복잡하거나 여러 단계로 얽혀 있으면 추론이 깨질 수 있어요. 이때는 반환 타입을 명확히 지정해보기.

구체적으로 이해를 돕기 위해 제가 작성한 함수 예시를 먼저 볼게요.

// 리스트 중 특정 키 값 필터하는 함수
// 제네릭 T, K를 받아서 필터 조건에 딱 맞게 타입 추론하게 만듦
function filterByKey<T, K extends keyof T>(list: T[], key: K, value: T[K]): T[] {
  return list.filter(item => item[key] === value);
}

// 호출 예시
const users = [
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 },
];

const filtered = filterByKey(users, 'age', 25); // T와 K가 자동 추론됨

여기서 중요한 건 K extends keyof T 부분이에요. 이로 인해 'age'나 'name' 같은 키 값만 받아서 안전하게 타입 체크가 되거든요. 실제로 이 함수 코딩할 때도 "K가 T의 키인지 반드시 검증"이 필수더라고요.

TypeScript 제네릭 타입 추론 헷갈렸던 부분 정리 직접 정리한 자료

TypeScript 제네릭 타입 추론 헷갈렸던 부분 정리 관련 정보

여기서 많이 틀립니다, 타입 추론이 안 될 때 체크리스트

그런데 여기서 막힌 게 "제네릭인데 왜 타입 추론이 안 될까?" 부분이었어요. 에러가 전혀 직관적이지 않았죠.

  • 매개변수 타입을 너무 광범위하게 선언했을 때 – 예를 들어 any나 unknown를 쓰면, 제네릭 추론이 무력화됩니다. 가급적 구체적으로 선언하세요.
  • 타입 매개변수 순서 헷갈림 – 가끔 function foo<T, U>(param: U): T처럼 매개변수와 제네릭 순서가 꼬이면 추론이 깨져요. 매개변수를 먼저 쓰는 제네릭부터 선언하거나, 명시적으로 타입 파라미터를 줘야 합니다.
  • 함수를 변수에 할당할 때, 타입 추론 범위 제한 – 화살표 함수 등으로 감쌀 때 자동 추론이 달라질 수 있어요. 이때는 함수 시그니처를 명확히 선언하는 게 좋습니다.
  • 객체를 바로 리터럴로 넘기면서 제네릭 호출하면 추론 실패 – 타입스크립트가 객체 리터럴을 모호하게 처리할 수 있어요. 잠깐 변수를 할당한 다음 넘기는 방법이 있답니다.
  • 조건부 타입과 조합할 때 너무 복잡하면 힌트를 줘야 함 – 조건부 타입이나 매핑 타입이 지나치게 복잡하면 TS가 타입을 못 추론하는 경우가 빈번해요.

예를 들어 이렇게 작성했다가 추론이 깨진 경험도 있어요.

function getValue<T, K>(obj: T, key: K): T[K] {
  return obj[key]; // 에러: 'K'는 'keyof T'에 할당할 수 없어요
}

// 해결하려면
function getValueFixed<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

'K extends keyof T'를 빼먹어서 발생한 에러였는데, 이런 기본 틀만 잘 챙겨도 큰 삽질을 줄일 수 있더라고요.

TypeScript 제네릭 타입 추론 헷갈렸던 부분 정리 참고 사진

TypeScript 제네릭 타입 추론 헷갈렸던 부분 정리 관련 정보

심화: 제네릭 타입 추론 최적화 꿀팁

기본 체크리스트를 확인했다면, 여기서 좀 더 편리하게 쓰는 노하우도 공유할게요.

  • 명시적 타입 인자 없이 편하게 쓰는 법 – 화살표 함수나 커링 함수 형태로 만들어두면, 타입스크립트가 함수 인자만으로도 제네릭을 추론하기 쉬워져서 호출이 훨씬 간편해집니다.
  • 조건부 타입으로 타입 좁히기 – 특정 조건에 따라 타입이 달라지게 만들면, 더 안전하고 편리한 타입 추론이 가능해져요. 예를 들어, 배열인지 아닌지에 따라 반환 타입을 다르게 주는 식이죠.
  • 유틸리티 타입과 조합 – Partial, Pick, Exclude 같은 기존 유틸리티 타입을 적극 활용하세요. 제네릭 타입도 조합 가능해서 코드 재사용성이 폭발합니다.

예시 코드를 보면서 이런 팁이 어디에 어떻게 작용하는지 볼게요.

// 커링 함수로 제네릭 타입 추론 돕기
function createGetter() {
  return function (obj: T, key: K): T[K] {
    return obj[key];
  };
}

const getUserValue = createGetter<{ name: string; age: number }>();
const user = { name: 'Carol', age: 28 };
const userName = getUserValue(user, 'name'); // 'name' 자동 추론

이렇게 하면 호출할 때 타입 인자를 따로 명시하지 않아도 알아서 추론이 되어 정말 편했어요.

자주 물어보시는 것들

Q. 제네릭에 any가 나와서 타입 안전성을 못 믿겠어요. 어떻게 해야 하나요?

A. 제네릭 타입이 any로 추론되는 건 대개 타입 제한을 제대로 걸지 않아서 그렇습니다. K extends keyof T처럼 제네릭에 조건을 걸어 타입 범위를 좁혀주세요. 그리고 가능하면 unknown과 조합해서 의도된 타입만 사용할 수 있게 관리하세요.

Q. 타입 추론이 안 되는데, 강제로 타입 인자를 지정하는 게 정답인가요?

A. 무조건 명시하는 게 좋은 건 아니에요. 우선 타입추론이 안 되는 이유가 뭔지 살펴보고, 간단히 매개변수 선언을 바꾸거나 타입 제한을 걸어 추론이 되도록 손보는 게 더 바람직합니다. 그래도 안 되면 명시적 타입 인자도 괜찮죠.

이번 글에서 소개한 체크리스트와 예시들을 차근차근 확인하면서 적용해보시면, TypeScript 제네릭 타입 추론 때문에 헤매는 시간은 훨씬 줄어들 겁니다. 저도 이걸 하나하나 겪으면서 많이 배웠어요.

Comments