[TS] void타입

김채운·2023년 3월 3일
0

Typescript

목록 보기
5/7

➡️ void

void는 어떤 값을 가지지 않는 것을 의미하며 return하지 않는 함수의 return 값 type으로 설정 가능하다. void는 결과 값을 반환하지 않는 함수에 설정하므로 undefined와 같다. 명시적으로 반환 값을 설정하지 않은 함수는 undefined를 반환하기에 typescript에서는 void를 명시한다.

function a () {

} 

const b = a()
  • a라는 function을 b 변수에다 넣고 커서 올려보면 void라고 타입이 뜬다. function a도 커서 올리면 void라고 반환값 타입이 추론이 된다.
function a ():void { 
    return '3';
}
  • 이렇게 void라고 타입을 정확하게 명시해 주고 return 값을 적어주면 return값에 error가 뜬다.(string 형식은 void에 할당할 수 없습니다.)
    즉, 함수의 return값이 void 타입이라는 것은, return값을 넣으면 안 되는 그런 함수라는 거다. 대신에, return 값으로 undefined는 된다. 하지만 null은 안 된다. 보통 그래서 return을 아예 안 적거나(return 값이 없거나), 아니면 그냥 return만 냅둔다. 이런 함수들이 return 타입이 void가 되는 것이다.

✌️ void의 두 가지 사용법

interface Human {
    talk: () => void;
}

const human: Human = {
    talk() {}
}

const human: Human = {
    talk() {return 'abc'}
}
  • 위에 talk가 void니까 밑에도 talk 메서드도 return 값이 없다. 또는 return undefined이나 아니면 그냥 return;이 될 수도 있다. 근데 여기서 우리를 헷갈리게 하는게, return 값으로 문자열인 'abc'를 반환시키는데 에러가 안 뜬다는 거다.

✏️ void 타입이 쓰이는 세 가지 종류 예시

------------1

function a(): void {

} 

------------2

interface Human {
    talk: () => void;
} // 메서드로 선언한 void

// ex)
interface Human {
    talk: () => void;
}
// 얘도 메서드잖아 하지만 이렇게 return값이 존재할 수 있음.
const human: Human = {
    talk() {return 'aba'}
}

------------3

function a(callback:() => void): void {

} //매개변수로 선언한 void 

// ex)
a(() => {
    return '3';
})// 이렇게! 이게 콜백인데 이것도 void인데 return값이 존재할 수 있지.
  • 이렇게 void에는 return 값 타입이 void인 것과, 매개변수가 void 함수가 들어간 것과, 메서드가 void 함수가 들어간 것 이렇게 세 가지 종류가 있다.
    신기하게도 매개변수가 void인 함수도 return값이 존재해도 에러가 뜨지 않는다.

그래서 void는 함수의 return 값이 void인 경우에만 return에 값이 있으면 에러가 나고 매개변수와 메서드 이 둘은 상관 없다. 이 두 가지는 왜 error가 안 나냐면, 애네한테서의 void의 의미는, 이 함수 또는 이 메서드의 return값을 사용하지 않겠다 그런 의미이다. ('사용하지 않겠다의 의미')
그리고 return값의 타입을 void로 명시한 경우는 직접적으로 return값이 없다는 의미이다.
그래서 같은 void이지만 의미가 다르다고 보면 된다.

✏️ void와 undefined의 차이

void는 반환 값이 없는 함수의 타입을 나타내고, undefined는 값이 할당되지 않은 변수의 타입이나 함수에서 명시적으로 undefined를 반환하는 경우의 타입을 나타냅니다.

let target: number[] =[];
function forEach(arr: number[], callback: (el: number) => undefined): void; 
//여기서 undefined면
forEach([1,2,3], el => target.push(el)); // target.push에서 에러가 날 수 밖에 없다.
  • 왜냐면 push하면 return값이 number다 그래서 콜백 함수인 el => target.push(el) 지금 얘의 return값은 number가 된다. 근데 여기 타입 정의를 undefined으로 해놨기 때문에, error가 뜨게된다(number는 undefined에 할당할 수 없다)
    만약 undefined를 number로 수정하면 당연히 error가 안 뜨겠지만 여기다 void로 선언해도 에러는 안 난다.
    왜냐하면 매개변수에서 쓰이는 void는 실제 return값이 뭐든간에 신경쓰지 않겠다 그런 의미이기 때문이다.(위에서 설명했듯이 return 값을 사용하지 않겠다는 뜻이기 때문)
    그래서 타입이 void냐 아니냐에 따라서 함수 표현이 좀 제한 된다.
interface A {
    talk: () => void;
}
const a:A = {
    talk() {return 3;}
}
const b = a.talk(); // 얘 타입 void 나옴.
  • 보통의 JS를 생각하면 b는 3이 나오는 게 맞는데 타입스크립트에서 지금같은 상황이면 메서드가 void인 경우에는 return값이 뭐든지간에 다 무시를 해버린다. 그래서 b 타입도 void가 뜬다. 이러면 문제가 되어버린다.
    그래서 애초에 void면 원칙적으로 returnr값을 넣으면 안 되는 게 맞다.

✏️ 강제 타입 변환 방법.

💡그래서 위와같은 경우에는 const b = a.talk() as number; 이런식으로 타입을 강제로 만들어줄 수 있는데, 그렇다고 항상 강제로 바꿔줄 수 있는 건 아니다. 왜냐, 이렇게 에러가 뜨기 때문. (void 형식을 number 형식으로 변환한 작업은 실수일 수 있습니다. 두 형식이 서로 충분히 겹치지 않기 때문입니다. 의도적으로 변환한 경우에는 먼저 'unknown'으로 식을 변환합니다.)
그렇기 때문에 내가 진짜 책임질 수 있다 하는 경우에만 const b = a.talk() as unknown as number 이렇게 바꿔줄 수 있다.

또 강제로 바꾸는 방법이 하나 더 있다.

const b = <number><unknown>a.talk(); 

하지만 이 방식보다는 as를 더 권장한다 그 이유는,
react에 jsx에서 <>이런 태그들이 사용이 되는데

<div></div>

이렇게, 그래서 이게 헷갈려서 타입스크립트가 잘 이해를 못 한다. 그렇기 때문에 react를 쓰게 될 경우 강제 타입 변환시에 as unknown as 형식으로 쓰는 게 더 좋다.

마지막으로 혹시

const b: number = a.talk() 

이렇게 타입을 강제해 줄 수도 있지 않을까 생각 할 수 있겠지만 "void 형식은 number 형식에 할당할 수 없다."라고 에러 뜨기 때문에 불가하다.

출처
제로초 올인원 타입스크립트 강의

0개의 댓글