인프런 커뮤니티 질문&답변
조건부타입소개 중 함수오버로딩 활용 시 인수의타입과 함수의 반환값의 타입이 깨지는 문제
해결된 질문
작성
·
26
·
수정됨
0
안녕하세요 .. 강의를 듣다 궁금한점이 생겨서 글 올리게 되었습니다.
function removeSpaces<T>(text: T): T extends string ? string : undefined;
function removeSpaces(text: any) {
if (typeof text === "string") {
return text.replaceAll(" ", "");
} else {
return undefined;
}
}
let result = removeSpaces("hi im winterlood");
// string
let result2 = removeSpaces(undefined);
// undefined궁금한점은 이부분인데요
오버로딩 시그니처에 현재 반환값에서만 타입을 조건부타입으로 제한하고있고,
제네릭을 선언한 부분에서는 따로 제한하고 있지않기때문에
호출 시 removeSpaces함수에 인자로 number타입의 값을 넣는경우
해당 함수의 반환값으로 undefined가 나올것이라 생각됩니다 ..
그럼 이때 함수의 인수에 대한 타입과(number) , 함수의 반환값에 대한타입이 (undefined) 깨져서(?)
해당함수가 이상한것같은데 ..! (타입안전하지 않다? 뭐라고 표현해야할까용 ...ㅠ)
제가 혹시 잘못생각한 부분이 있을까요 ??
답변 1
0
안녕하세요 히수님 이정환입니다.
우선 말씀하신대로 removeSpaces 함수에 number 타입의 인수를 전달하는 경우 반환값으로는 undefined가 리턴됩니다. 잘못 생각하신 부분은 없어요!
다만 이게 "타입이 깨진다"거나 "타입 안전하지 않다"고 보기는 어렵습니다. 왜냐하면 number를 넣었을 때 반환 타입이 undefined로 추론되는 것 자체가 조건부 타입이 의도한대로 정확히 동작하고 있는 거거든요. number extends string은 거짓이니까 undefined가 나오는 게 맞는 거죠. (실제로 undefined 값이 반환되기도 하니까요)
제네릭에 별도의 제약을 걸지 않은 건, 조건부 타입 자체가 어떤 타입이 들어오든 그에 맞는 반환 타입을 유연하게 결정해주는 역할을 하기 때문입니다. 즉 string이 오면 string, 그 외에는 undefined — 이렇게 알아서 분기해주는 게 조건부 타입의 목적이에요.
물론 실무에서 이 함수를 더 엄격하게 만들고 싶다면 function removeSpaces<T extends string | undefined>(text: T) 처럼 제네릭에 제약을 추가할 수도 있습니다. 하지만 강의에서는 조건부 타입의 동작 원리를 설명하는 데 초점을 맞추고 있기 때문에, 제네릭 제약까지는 다루지 않은 것이니 참고해주세요!
여기서 핵심은, 반환 타입이 T 그 자체가 아니라 T extends string ? string : undefined라는 조건부 타입이라는 점이에요.
즉 T는 여전히 하나의 타입(number)이지만, 반환 타입은 T를 그대로 쓰는 게 아니라 T를 조건으로 "평가"해서 새로운 타입을 만들어내는 거죠. T가 number니까 → number extends string은 거짓 → undefined가 반환 타입이 되는 겁니다. T가 변한 게 아니라, T를 기반으로 별도의 타입을 계산한 거예요.
그래서 "입력 타입과 반환 타입이 달라지도록 제네릭을 사용하는 게 올바른 방식인가?"에 대해서는 상황에 따라 다릅니다.
만약 입력값을 그대로 반환하는 함수라면 <T>(x: T): T처럼 입출력 타입이 같아야 하지만, 이 예제처럼 입력 타입에 따라 반환 타입이 달라지는 함수라면 조건부 타입으로 반환 타입을 따로 계산하는 게 오히려 정확한 방식입니다. 실제로 실무에서도 이런 패턴을 자주 쓰거든요.
function fetchData<T>(input: T): T extends string ? Response : undefined;예를 들어 위 코드와 같이 API 응답을 처리할 때 이런 식으로 string(URL)이 들어오면 Response를 반환하고, 그 외에는 undefined를 반환하는 함수를 만들 수 있습니다. 입력 타입에 따라 반환 타입이 달라지지만, 이것도 제네릭의 올바른 활용이에요
아하 말씀해주신 내용을 보았을때,
제네릭의 기본사용방법은 T가 사용된 모든 위치에서 동일한 타입을 가리키는것이 맞지만,
이 예제의 경우 조건부타입을 사용한 예제이기 때문에 반환타입은 초기타입 T를 그대로 사용하는것이 아니라,
T를 기반으로 계산된 타입이라서 서로 다르게 보이는 것이 맞다는 말씀이시네요..!
질문 처음 드려보는데 친절하게 답변해주셔서 감사합니다.
덕분에 개념이 많이 정리되었습니다.





답변 감사합니다.
조건부 타입의 동작 원리를 설명하기 위한 예제라는 점은 이해하고 있습니다.
다만, 이전 강의들에서 다뤄진 여러 개념들이 함께 사용된 예제라
각각의 기능을 정확히 이해하고 싶어 질문드립니다.
사실상 이 질문은 제네릭에 대한 질문입니다..!
저는 <T> 선언부, 매개변수 타입 T, 그리고 반환 타입의 T가
모두 하나의 동일한 타입을 가리키기 때문에,
만약 하나가 string이면 모두 string,
하나가 number이면 모두 number가 되어야 한다고 생각했습니다.
근데 예제를 보면 인수에 대한 타입과(number) , 함수의 반환값에 대한타입이 (undefined) 서로 상이한데 ..
이렇게 입력 타입과 반환 타입이 달라지도록 제네릭을 사용하는 것도 올바른 방식인지 궁금합니다.