1. enum타입
enum 타입이란? 열거형 타입이라고도 불리고, 여러 가지 값들에 각각 이름을 부여해 열거해 두고 사용하는 타입을 말한다.
javascript에는 존재하지 않고, typescript에서만 제공하는 특별한 타입이다.
const user1 = {
name: '김도현',
role: 0, // 0 <- 관리자
};
const user2 = {
name: '김묨뮴',
role: 1, // 1 <- 일반유저
};
const user3 = {
name: '김밈뭄',
role: 2, // 2 <- 게스트
};
이런식으로 숫자로 권한을 부여하는 경우들이 존재하는데, 개발을 쭉 진행하다 보면, 2번이 관리자인가? 와 같이 헷갈리는 경우들이 존재하게 된다.
이럴 때 enum 타입을 사용하면 좋다.
enum Role {
ADMIN = 0,
USER = 1,
GUEST = 2,
}
const user1 = {
name: '김도현',
role: Role.ADMIN, // Role.ADMIN -> 0
};
const user2 = {
name: '김묨뮴',
role: Role.USER, // Role.USER -> 1
};
const user3 = {
name: '김밈뭄',
role: Role.GUEST, // Role.GUEST -> 2
};
추가적으로,
enum Role {
ADMIN,
USER,
GUEST,
}
위처럼 코드를 작성할 시 따로 숫자를 지정안해줘도 순서대로 0, 1, 2가 각각 들어가게 된다.
ADMIN을 10부터 USER를 11, GUEST를 12로 하고 싶다면,
enum Role {
ADMIN = 10,
USER,
GUEST,
}
위처럼 한 경우, 10 부터 +1한 값이 차례대로 들어가게 된다.
중간에 USER만 10으로 지정해준다면?
ADMIN은 0번, USER는 10, GUEST는 11로 값이 할당된다.
Enum을 사용할 때에는 숫자를 자동으로 할당시킬 수도 있고 직접 시작하는 숫자를 지정해 줄 수도 있다.
Enum은 숫자뿐만 아니라, string도 가능하다.
enum Language{
korean="ko",
english="en",
}
const user1 = {
name: '김도현',
role: Role.ADMIN, // Role.ADMIN -> 0
Language:Language.korean
};
Q. TypeScript에서 타입에 관련한 부분들은, 컴파일 시에 없어진다고 알고 있는데, Role.ADMIN처럼 값으로 사용하는데 없어지는 게 가능한가?
A. Enum은 컴파일 시 사라지지 않는다.
tsc로 컴파일을 해보면
var Role;
(function (Role) {
Role[Role["ADMIN"] = 0] = "ADMIN";
Role[Role["USER"] = 1] = "USER";
Role[Role["GUEST"] = 2] = "GUEST";
})(Role || (Role = {}));
var Language;
(function (Language) {
Language["korean"] = "ko";
Language["english"] = "en";
})(Language || (Language = {}));
const user1 = {
name: '김도현',
role: Role.ADMIN, // Role.ADMIN -> 0
Language: Language.korean,
};
enum으로 선언한 Role 또는 Language는 사라지지 않고, 객체로 선언되어 사용되는 것을 볼 수 있다.
2. Any타입과 Unknown 타입
1. Any
any타입은 우리가 특정 변수의 타입을 우리가 확실히 모를 때 사용한다.
any타입을 써야 하는 예시를 설명하자면,
let anyVar = 10;
anyVar = 'hello'; //'string' 형식은 'number' 형식에 할당할 수 없습니다.ts(2322)
예를 들어 처음에 선언할 때에는 number를 넣고, 나중에는 string을 넣고 싶은 변수가 존재한다고 칠 때, 위처럼 코드를 작성하게 된다면, 오류가 발생하게 된다.
TypeScript에서는 처음 선언할 때, 따로 타입을 지정해주지 않아도, 초기화하는 값을 기준으로 변수의 타입을 추론하여 자동으로 타입이 지정된다.
let anyVar: any = 10;
anyVar = 'hello';
anyVar = true;
anyVar = {};
anyVar = () => {};
anyVar.toUpperCase();
anyVar.toFixed();
let num: number = 10;
num = anyVar;
이처럼 타입을 any로 지정되게 되면, JavaScript 변수처럼 모든 타입의 변수로 활용이 가능하다. 모든 타입뿐만 아니라, 문자열만 가능한 문자열 전용 메서드, 숫자 변수에 대입, 함수 등 다양한 모든 것이 가능하다.
즉 any타입은 모든 타입이 가능한 치트키 같은 타입이다.
하지만 위처럼 코드를 작성 후 실행시키게 되면 오류가 발생하게 된다.
anyVar = () => {};
anyVar.toUpperCase();
함수로 지정한 후, 문자열 전용 메서드를 사용하기 때문에 실행은 되지만, runtime에러가 발생하게 된다.
즉 any타입은 JavaScript에서 발생하는 변수 타입에 관련한 단점과 같이, TypeScript에서 가지는 이점을 모두 포기하는 타입이기에 최대한 사용을 지양해야 한다.
2. unknown
unknown타입은 any와 마찬가지로 변수에 어떤 타입이 들어올지 모르는 경우에 사용하게 된다.
//unknown
let unknownVar:unknown;
unknownVar = 'hello';
unknownVar = true;
unknownVar = 1;
unknownVar = () => {};
unknownVar도 any와 마찬가지로 다른 타입의 값으로 저장하여도 오류가 발생하지 않는 것을 볼 수 있다.
//unknown
let unknownVar:unknown;
let num: number = 10;
num = unknownVar; // 'unknown' 형식은 'number' 형식에 할당할 수 없습니다.ts(2322)
any타입과의 차이점으로는, unknown타입인 변수를 다른 변수에 저장하는 것은 안된다.
Unknowntype은 NumberType인 변수에 저장할 수 없으며, NumberType인 변수 이외의 모든 타입의 변수에다 UnknownType의 값을 집어넣을 수가 없다.
let unknownVar: unknown;
unknownVar = 1;
unknownVar = () => {};
unknownVar.toUpperCase(); //'unknownVar'은(는) 'unknown' 형식입니다.ts(18046)
unknown은 any타입과 다르게 타입전용 메서드들도 사용할 수 없다.
unknown을. toUpperCase()과 같은 문자열 전용 메서드를 사용하거나, Number Type만 가능한 사칙연산을 해야 한다면,
let num: number = 10;
if(typeof unknownVar==="number"){
num=unknownVar;
}
이처럼 확실한 타입을 밝히는 타입 정제과정을 거친 후, 사용이 가능하다.
타입 종류 | any | unknown |
---|---|---|
다음에 어떤 타입이 들어와도 상관없는 타입 | O | O |
타입이 정해진 변수에 대입이 가능한지 | O | X |
특정 타입 전용 메서드를 사용이 가능한지 | O | X |
3. Void 타입과 Never 타입
1. void
void타입은 말 그대로 공허, 아무것도 없다는 것을 뜻한다.
function fun1():string{
return "hello";
}
타입스크립트에서는 함수의 return값의 타입도 지정할 수 있다.
return 값이 없는 경우에 타입은 어떻게 지정해야 할까?
function fun2():void {
console.log('hello');
}
let a: void;
a = 1; //'number' 형식은 'void' 형식에 할당할 수 없습니다.ts(2322)
a = 'hello'; // 'string' 형식은 'void' 형식에 할당할 수 없습니다.ts(2322)
a = {}; //'{}' 형식은 'void' 형식에 할당할 수 없습니다.ts(2322)
a = undefined;
이처럼 fun2()와 같이, 리턴값이 없는 함수의 경우 void로 지정할 수 있다.
변수에도 void를 지정해 줄 수 있는데, 변수의 타입을 void로 지정하게 되면, undefuned 빼고 어떤 타입의 변수도 담을 수 없게 된다.
단, tsconfig에서 엄격한 nullcheck를 false로 두면,
{
"compilerOptions": {
...
"strictNullChecks": false,
...
},
}
void변수에도 a=null; null값을 담을 수 있다.
Q. undefined와 null도 아무것도 없는 타입을 말하는데, 굳이 void를 써야 함?
A. fun2()의 반환값을 undefined로 하게 되면 return undefined;을 해야 하고, null을 반환하는 값 타입을 null로 지정하면 return null;으로 null을 반환해야 한다.
그렇기에 아무것도 반환하지 않는 경우 void를 사용하는 것이다.
2. never
never타입은 "존재하지 않는", 불가능한 타입을 말한다.
function func3(): void {
while (true) {}
}
fun3의 경우 무한 반복하는 함수로서 반환자체를 하지 않는다. 위에서 설명하던 func1과 func2는 반환하는 값이 없기 때문에 void로 두었다면, fun3는 반환하는 값이 없는 것이 아닌, 반환 자체를 하지 않는다.
반환자체를 하지 않는데, 반환하는 값이 없는 void를 사용한다? 말 자체가 모순이라고 느껴진다.
그렇기 때문에 fun3의 함수처럼 절대로 정상적으로 종료될 수 없는 함수는 never타입으로 작성해줘야 한다.
function func3(): never {
while (true) {}
}
function fun4(): never {
throw new Error();
}
let anyVar: any;
let a: never;
a = 1; //'number' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)
a = 'hello'; //'string' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)
a = {}; //'{}' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)
a = undefined; //'undefined' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)
a = null; //'null' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)
a= anyVar; //'any' 형식은 'never' 형식에 할당할 수 없습니다.ts(2322)
fun4와 같이 error를 반환하는 함수의 경우도 never를 사용하며, never타입으로 지정한 a에는 void와 다르게 undefined도, null, any도 모두 지정할 수 없다.
즉 never타입은 변수타입에 활용하면 어떤 값도 저장할 수 없는 저장하는 것조차 성립하지 않는 타입을 정의할 때에 활용하게 된다.
- 이 포스팅은 '이정환 - 한 입 크기로 잘라먹는 타입스크립트 (인프런)' 강의를 참고하여 작성되었습니다.
'TypeScript' 카테고리의 다른 글
[TypeScript] 타입스크립트 타입 별칭과 인덱스 시그니처 (type alias & index signature) (0) | 2024.09.27 |
---|---|
[TypeScript] 타입스크립트 객체 (Property 기반 타입 시스템 / 선택적 Property (2) | 2024.09.26 |
[TypeScript] 타입스크립트 배열과 튜플 (배열과 튜플의 차이점) (0) | 2024.09.25 |
[TypeScript] 타입스크립트 기본 타입 (원시타입과 리터럴타입) (0) | 2024.09.24 |
[TypeScirpt] 타입스크립트 컴파일러 옵션 설정 (0) | 2024.09.21 |