Day 4 진도에 해당되는 강의를 듣고 unknown, never, void, any 타입에 대해 정리해보았습니다.
any
, unknown
, void
, never
같은 타입을 이해하려면, 먼저 타입 간의 관계를 이해할 필요가 있습니다. 이때 자주 등장 하는 개념으로 슈퍼타입
, 서브타입
, 업 캐스팅
, 다운 캐스팅
이 있습니다.
슈퍼타입
은 더 일반적이고 넓은 범위의 타입입니다. 여러 서브타입들을 포괄하는, 말 그대로 “상위 타입”
입니다.number
는 1, 2, 10, 1.5, Infinity 등 모든 숫자 값을 포함할 수 있는 타입입니다.number
는 더 넓은 개념이므로 10
의 슈퍼타입입니다.서브타입
은 슈퍼타입보다 더 구체적이고 좁은 범위의 타입입니다.10
이라는 숫자 하나만 허용하는 number literal type
은 number
보다 범위가 좁기 때문에, 10
은 number의 서브타입
입니다.let num1: number = 123;
const b: 10 = 10;
const c: 10 = 20; // ❌ Error: 20은 10의 서브타입이 아님 (다른 리터럴이기 때문)
타입 간의 변환을 설명할 때 자주 쓰이는 개념이 업 캐스팅(up casting)
과 다운 캐스팅(down casting)
입니다. 쉽게 말하면, 타입을 넓게
또는 좁게
바꾸는 것입니다.
const subNum: 10 = 10;
let superNum: number = 123;
superNum = subNum; // 10 -> number (업 캐스팅)
const num: number = 10;
const literal: 10 = num as 10; // number -> 10 (다운 캐스팅)
More on Functions#unknown - TypeScript Handbook 보러가기
unknown
타입은 정확한 타입을 알 수 없지만 일단 뭔가는 들어올 수 있는 타입입니다. 어떤 값이 있을 수는 있지만, 그 값의 타입을 알 수 없음을 나타냅니다. any
와 비슷해 보이지만, unknown
타입의 값은 타입을 확정하지 않으면 사용할 수 없습니다. 그래서 값을 사용하기 전에 타입을 검사해야 합니다.
let input: unknown = 'hello';
if(typeof input === 'string') {
console.log(input.toUpperCase());
}
모든 타입(any, object, void, undefined, null, never)의 값의 슈퍼타입입니다. 그래서 모든 타입의 값을 할당 받을 수 있습니다. 업 캐스팅이 가능합니다.
function handleInput(data: unknown) {
if(typeof data === 'number'){
console.log(data.toFixed(2));
}
}
unknown
타입의 값은 타입 정제 없이 직접 사용할 수 없습니다.unknown
은 타입 안전성을 유지하면서 유연하게 코딩할 수 있게 해줍니다.never
타입은 "절대 반환되지 않는 값"
을 의미합니다.
예를 들어, 정상적으로 종료되지 않거나, 영원히 실행되거나, 오류를 던지는 함수가 대표적입니다.
function throwError(message: string): never {
throw new Error(message);
}
function loopFunc(): never {
while(true) {
// ...
}
}
never
타입은 아무 값도 가질 수 없는 타입이기 때문에, 모든 타입(any, unknown, object, void, undefined, null, never)의 서브타입으로 간주됩니다. 그래서 never
타입을 가진 값을 다른 타입(any, unknown, string, number, boolean 등)의 변수에 할당할 수는 있습니다.
function neverFunc(): never {
while (true) {}
}
// up casting
let anyVar: any = neverFunc();
let unknownVar: unknown = neverFunc();
let obj: { name: string } = neverFunc();
let voidVar: void = neverFunc();
let undefinedVar: undefined = neverFunc();
let nullVar: null = neverFunc();
let num: number = neverFunc();
let str: string = neverFunc();
let bool: boolean = neverFunc();
하지만 반대로, 다른 타입의 값을 never
타입 변수에 할당하는 것은 허용되지 않습니다.
let a: never = 'hello'; // ❌ Error!
a = 123; // ❌ Error!
a = false; // ❌ Error!
a = null; // ❌ Error!
a = undefined; // ❌ Error!
a = { name: 'Lucy' }; // ❌ Error!
무한 루프
등으로 종료되지 않거나 예외를 던질 때
사용합니다.// 아래 코드는 모두 Error가 발생합니다.
let never1: never = 1;
let never2: never = "string";
let never3: never = true;
never
로 남아 오류가 발생할 수 있습니다.More on Functions#void - TypeScript Handbook 보러가기
void
는 반환값이 없다는 걸 의미하는 타입입니다. 주로 함수의 반환 타입으로 사용되며, 반환값이 없음을 명확히 합니다.
function logMessage(message: string): void {
console.log(message);
}
const arr: number[] = [1, 2, 3];
const callbackFn = (value: number, index: number): void => {
console.log(`${index + 1} 번째 요소: ${value}`);
};
arr.forEach(callbackFn);
void
는 변수 타입으로는 거의 사용하지 않습니다.undefined
와 유사하지만, 의도적으로 아무것도 반환하지 않는다
는 의미를 담고 있습니다.void
는 undefined
의 슈퍼타입이라 업 캐스팅의 개념에 의해 void
함수에 return undefined
는 허용됩니다.function logMessage(message: string): void {
console.log(message);
return undefined;
}
Everyday Types - TypeScript Handbook 보러가기
any
타입은 TypeScript의 타입 시스템을 우회하여, 해당 변수에 어떤 타입의 값이든 할당할 수 있도록 허용하는 타입입니다. 즉, 타입 검사를 하지 않겠다는 의미로 기존의 자바스크립트를 쓰는 것과 동일합니다.
모든 타입(never를 제외한 unknown, object, void, undefined, null 타입)의 값을 할당할 수 있는 타입으로 다운 캐스팅, 업 캐스팅이 가능합니다.
let anyVar: any;
let unknownVar: unknown;
let voidVar: void = () => { console.log('hello'); };
anyVar = unknownVar;
anyVar = { name: 'Lucy' };
anyVar = voidVar;
anyVar = undefined;
anyVar = null;
anyVar = 123;
anyVar = 'hello';
anyVar.foo();
any
를 사용하면 타입스크립트의 타입 시스템을 무력화 시킵니다.any
사용을 남용하면, 결국 자바스크립트와 다를 바 없는 코드가 됩니다.이번에 unknown
, never
, void
, any
타입을 정리하면서 그동안 막연하게 알고 있던 개념들을 좀 더 확실히 이해할 수 있었습니다.
any
와 void
는 평소에도 종종 보며 대략적인 용도는 알고 있었지만, unknown
과 never
는 “이게 왜 필요하지?”, “언제 써야 하지?” 라는 의문만 남은 채 정확하게 쓰지 못했던 타입이었습니다. 이번에 강의를 듣고 정리하는 과정을 통해, 이 네 가지 타입이 각각 어떤 의미를 갖고 있고, 어떤 상황에서 사용해야 하는지를 배울 수 있었습니다.
any
는 타입 검사를 하지 않고 어떤 값이든 허용하고 싶을 때 사용하지만, 타입 안정성을 잃게 되므로 실제 프로젝트에서는 지양하려고 합니다. 다만, JavaScript 프로젝트를 TypeScript로 점진적으로 마이그레이션할 때는 일시적으로 사용할 수 있을 것 같습니다.void
는 함수가 아무 값도 반환하지 않을 때 사용하는 타입으로, 이번 기회에 다시 한 번 복습할 수 있었습니다.unknown
은 값은 존재하지만 타입을 정확히 알 수 없을 때 사용하는 타입으로, 타입 정제를 통해 안전하게 다룰 수 있다는 점을 배울 수 있었습니다.never
는 무한 루프나 예외 처리처럼 함수가 정상적으로 종료되지 않는 경우에 사용하는 타입이라는 것도 알게 되었습니다.이번 학습을 통해 앞으로 프로젝트에서 이 4가지 타입을 마주하게 되더라도, 용도나 의미를 몰라서 당황하는 일 없이 사용할 수 있을 것 같습니다.
평일 중에 이 글은 보지 못했는데..! 이번주 정말 부지런하게 공부하셨군요!
덕분에 unknown, never, any 라는 신기한 타입을 알게 되었습니다.
그나마 void 반환을 간간이 쓰는데
콜백 함수의 반환 타입으로도 자주 등장한다. 정말 그렇네요!