인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

ReKoding님의 프로필 이미지
ReKoding

작성한 질문수

한 입 크기로 잘라먹는 타입스크립트(TypeScript)

void 타입 질문 드립니다

해결된 질문

작성

·

425

2

안녕하세요 강사님 !

리액트 강의 듣고 너무 좋아서 타입스크립트 까지 공부하고 있습니다 !!

void 타입 관련하여 궁금한 사항이 있어서 질문 드립니다.

 

제가 알기로는 void 타입은 반환 값이 없을 때 사용하는 타입으로 알고 있습니다.

(현재 5.1 버전부터는 함수의 반환 값이 없을 때 자동으로 undefined가 반환되니, undefined 타입을 반환 값으로 넣어줘도 문제가 없다고 알고 있습니다.)

 

아래와 같이 반환 값이 void 타입으로 설정하면 반환 값이 있으면 에러가 나야 맞는거 같은데, 반환 값으로 전달 받은 매개변수를 던져줘도 에러가 발생하지 않고 msg가 반환되는데 이게 어떻게 가능한걸까요..?

제가 잘못 이해하거나 잘못 작성한게 있는걸까요??

 

const hello: (msg: string) => void = (msg) => {
  return msg
};
const h1 = hello('테스트');
console.log(h1); // '테스트'

답변 1

1

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

안녕하세요 이정환입니다.

먼저 엄청나게 예리하시군요! 강의중에는 혼동을 불러 일으킬 수 있을 것 같아 설명드리지 않았는데 대단하십니다.

우선 다음과 같이 함수의 반환값 타입을 명시적으로 void로 정의하면 void 타입은 함수가 아무것도 반환하지 못하도록 강제합니다.

// sample 함수의 반환값 타입을 명시적으로 void로 정의 함
function sample () : void{
  return 1;
  // ^^^ 오류 발생!
}

그러나 놀랍게도 다음과 같이 문맥적 타이핑을 이용해 함수의 타입을 정의할 때에는 void 타입은 함수가 아무것도 반환하지 못하도록 강제하지 않습니다.

type Sample = () => void;

const sample : Sample = ()=>{
  return '123123'
  // void 타입임에도 오류가 발생하지 않음
}

이때 참고로 문맥적 타이핑이라는 것은 타입스크립트가 코드의 문맥을 파악해 타입을 추론하는 경우를 말합니다.

위 코드의 sample 변수의 타입이 () => void 라는 함수 타입이기 때문에 타입스크립트가 문맥상 추론하여 sample 변수에 저장되는 함수의 반환값 타입이 void일 것이라고 추론한다고 이해하시면 됩니다.

(쉽게 말해 첫번째 코드처럼 함수 자체에 반환값 타입을 명시하지 않았음에도 문맥상 그렇게 추론되는 것을 말합니다.)

어쨌든 앞서 말씀드린 것 처럼 타입스크립트는 문맥적 타이핑 상황에서는 함수의 반환값 타입이 void로 추론되더라도 다른 타입의 값을 반환할 수 있게 됩니다. 이것은 버그가 아니며타입스크립트의 기능 중 하나입니다.

다만 다음 코드처럼 반환된 값은 void 타입으로 취급되기 때문에 아무런 곳에서도 이용될 수 없습니다.

type Sample = () => void;

const sample : Sample = ()=>{
  return '123123'
}

const res = sample();
// void로 추론 됨 -> 아무런 용도로도 활용 불가

res +1;
// ^^^ 오류

이렇게 설계된 이유는 몇몇 JavaScript 메서드를 지원하기 위함인데요 가장 대표적인 예시로 배열의 forEach 메서드가 있습니다.

forEach 메서드는 요소들을 순회하기만 할 뿐 뭔가를 반환하지는 않기 때문에 다음과 같이 콜백 함수의 반환값 타입은 void로 구현되어 있습니다.

(callbackfn: (...) => void, thisArg?: any): void

이때 다음과 같이 forEach를 활용해 기존 배열에서 새로운 배열로 데이터를 복사하는 과정을 생각해보겠습니다.

const oldArr=[1,2,3];
const newArr=[];

oldArr.forEach((item)=>{newArr.push(item)})

자주 사용되는 방식이죠? 그런데 이렇게 사용하는 경우도 꽤 잦습니다.

const oldArr=[1,2,3];
const newArr=[];

oldArr.forEach((item)=>newArr.push(item))
// 화살표 함수를 이용하니까 중괄호는 제거

타입스크립트 환경에서 위 코드를 작성해도 아무런 오류도 발생하지 않습니다.

그런데 이때 만약 void 타입이 문맥상 타이핑 상황에서도 함수가 아무런 값도 반환하지 못하도록 강제한다면 오류가 발생했을 겁니다. 왜냐면 forEach의 콜백함수에서 다른 함수를 반환하고 있으니까요

그래서 이런 상황에서는 반환값이 void 타입임에도 값을 반환하는 것을 허용하도록 설계된 것 입니다. JavaScript의 기존 메서드들이나 각종 기능들을 문제 없이 이용할 수 있도록 말이죠

이렇게 허용한다고 해도 문제가 발생할 일은 없습니다. 어짜피 forEach 메서드는 콜백함수가 반환한 값을 이용하지 않기 때문입니다.

ReKoding님의 프로필 이미지
ReKoding
질문자

오오 정말 상세한 설명 감사드립니다 !! ㅎㅎ

typescript에서 만들어진 map, forEach 함수를 보니까 확실히 이해가 빠르게 가는 것 같아요!

저는 처음에 '오류가 아닐까?' 와 '이럴거면 void가 필요할까?' 라는 생각을 했는데, 자바스크립트의 기능들을 참고해서 설계된 것이라는 게 느껴집니다 !!

 

좋은 정보 감사합니다 ㅎㅎ 👍👍

ReKoding님의 프로필 이미지
ReKoding

작성한 질문수

질문하기