any 타입
any 타입은 자바스크립트에 존재하는 모든 값을 오류 없이 받을 수 있다.
타입스크립트는 동적 타이핑 특징을 가진 자바스크립트에 정적 타이핑을 적용하는 것이 주된
목적이지만 any 타입은 이러한 목적을 무시하고 동적 타이핑으로 돌아가는 것과 비슷한 결과를
가져온다. 따라서 any 타입을 변수에 할당하는 것은 지양행 할 패턴으로 알려져 있다.
그럼에도 any 타입을 사용해야 할 때가 있는데 대표적으로 3가지 사례를 들 수 있다.
1. 개발 단계에서 임시로 값을 지정해야 할 때
복잡한 구성 요소로 이루어진 개발 과정에서 추후 값이 변경될 가능성이 있거나 아직 세부
항목에 대한 타입이 확정되지 않은 경우가 생길 수 있다. 이럴 때 해당 값을 any로 지정하면 경고
없이 개발을 계속할 수 있어 타입을 명시하는 데 소요되는 시간을 절약할 수 있다.
2. 어떤 값을 받아올지 또는 넘겨줄지 정할 수 없을 때
자바스크립트에서는 어떤 값의 타입을 명확하게 지정하기 어려운 상황이 발생할 수 있다.
예를 들어 API 요청 및 응답 처리, 콜백 함수 전달, 외부 라이브러리 등을 사용할 때는 어떤 인자를
주고받을지 특정하기 힘들다. 이처럼 주고받을 값이 명확하지 않을 때 열린 타입(any 타입)을
선언해야 할 수 있다.
3. 값을 예측할 수 없을 때 암묵적으로 사용
외부 라이브러리나 웹 API의 요청에 따라 다양한 값을 반환하는 API가 존재할 수 있다.
이렇게 예외적으로 any 타입을 사용해야 하는 상황이 있음에도 any 타입은 타입 검사를 무색하게
만들고 잠재적으로 위험을 초래할 가능성이 커지게 하므로 지양하는게 좋다.
unknown 타입
unknown 타입은 any 타입과 유사하게 모든 타입의 값이 할당될 수 있다.
그러나 any를 제외한 다른 타입으로 선언된 변수에는 unknown 타입 값을 할당 할 수 없다.
unknown 타입은 기존 타입 시스템에서 부족한 부분을 보완하기 위해 등장했다.
const unknownFunc: unknown = () => {
console.log("unknwon");
};
unknownFunc(); // Error: Object is of type 'unknown'
예제를 보면 함수를 unknwon 타입 변수에 할당할 때는 컴파일러가 아무런 경고를 주지 않지만
이를 실행하면 에러가 발생하게 된다. 이는 함수뿐만 아니라 객체의 속성 접근, 클래스 생성자
호출을 통한 인스턴스 생성 등 객체 내부에 접근하는 모든 시도에서 에러가 발생한다.
unknown 타입은 어떤 타입이 할당되었는지 알 수 없음을 나타내기 때문에 unknown 타입으로
선언된 변수는 값을 가져오거나 내부 속성에 접근할 수 없다. 이는 unknown 타입으로 할당된
변수는 어떤 값이든 올 수 있음을 의미하는 동시에 개발자에게 엄격한 타입 검사를 강제하는 의도
를 담고있다.
앞에서 살펴본 any 타입을 사용하는 사례에서 나중에 any타입을 특정 타입으로 수정해야 하는
것을 누락하면 어떤 값이든 전달될 수 있기 때문에 런타임에 예상치 못한 버그가 발생할 수 있다.
unknown 타입은 이러한 상황을 보완하기 위해 등장한 타입이다. any타입과 유사하지만 타입
검사를 강제하고 타입이 식별된 후에 사용할 수 있기 때문에 any 타입보다 더 안전해 데이터
구조를 파악하기 힘들 때 any 타입을 대체해 사용하는 방법이 권장된다.
void 타입
함수에는 전달되는 매개변수의 타입과 반환하는 타입을 지정해줘야 한다.
타입스크립트에서는 함수가 어떤 값을 반환하지 않는 경우에 void를 지정해 사용한다고 생각하면
된다.
void 타입은 주로 함수 반환 타입으로 사용되지만 함수에 국한된 타입은 아니며 변수에도 할당 할
수 있다. 그러나 함수가 아닌 값에 대해서는 대부분 무의미하다.
never 타입
never 타입은 값을 반환할 수 없는 타입을 말한다. 함수와 관련하여 많이 사용되는 타입이며
값을 반환하지 않는 것과 없는 것을 명확히 구분해야 한다.
자바스크립트에서 값을 반환할 수 업는 예는 크게 2가지로 나눌 수 있다.
에러를 던지는 경우
자바스크립트에서는 런타임에 throw 키워드로 에러를 발생시킬 수 있는데, 이는 값을 반환하는
것으로 간주하지 않는다. 따라서 특정 함수가 실행 중 마지막에 에러를 던지는 작업을 수행한다면
해당 함수의 반환 타입은 never이다.
무한히 함수가 실행되는 경우
무한 루프는 결국 함수가 종료되지 않음을 의미하기 때문에 값을 반환하지 못한다.
never 타입은 모든 타입의 하위 타입이다.
즉, 자신을 제외한 어떤 타입도 never 타입에 할당될 수 없다는 것을 의미한다. (any 타입이라도)
Array 타입
자바스크립트에서는 배열을 객체에 속하는 타입으로 분류해 배열을 단독으로 배열이라는
자료형에 국한하지 않는다. 또한 타입스크립트에서 Array 타입을 사용하기 위해서는
타입스크립트의 특수한 문법을 함께 다뤄야 한다.
대개 정적 타입의 언어에서는 배열을 선언할 때 타입과 크기까지 동시에 제한하기도 한다.
타입스크립트에서는 일반적으로 배열의 크기까지 제한하지는 않지만 명시적인 타입을 선언하여
해당 타입의 원소를 관리하는 것을 강제한다. 자료형[] 형식을 사용해 배열 타입을 선언할 수 있다.
const array : number[] = [1, 2, 3];
Array 키워드로 제네릭 문법을 사용해 배열 타입을 선언하는 방법도 있으며
두 방식 간의 차이점은 선언하는 형식 외에는 없다.
const array: Array<number> = [1, 2, 3];
기본적으로 자바스크립트의 동작은 배열 원소의 타입을 구분하지 않기 때문에 다양한 자료형의
원소를 함께 다룰 수 있는데, 이럴때에는 유니온 타입을 사용할 수 있다.
const array1: Array<number | string> = [1, "string"];
const sadf: (number | string)[] = [1, "string"];
타입스크립트에서의 배열과 튜플은 자바스크립트와 달리 제한적으로 쓰인다.
배열은 사전에 허용하지 않은 타입이 서로 섞이는 것을 방지하여 타입 안정성을 제공하고
튜플은 길이까지 제한하여 원소 개수와 타입을 보장한다.
스프레드 연산자를 사용해 튜플과 배열의 성질을 혼합해서 사용할 수 있으며 옵셔널 프로퍼티
또한 사용이 가능하다.
const mixed: [number, string, ...string[]] = [1, "A", "B", "C"];
let arr: [number, string, string?];
arr = [1, "A"];
arr = [1, "A", "B"];
enum 타입
enum 타입은 열거형이라고도 부르는데 타입스크립트에서 지원하는 특수한 타입이다.
enum은 일종의 구조체를 만드는 타입 시스템이다. enum을 사용해서 열거형을 정의할 수
있는데 열거형은 각각의 멤버를 가지고 있다. 타입스크립트는 각 멤버의 값을 스스로 추론한다.
기본적인 추론 방식은 숫자 0부터 1씩 늘려가며 값을 할당하는 것이다.
enum ProgramingLanguage {
TS,
JS,
Java,
Python,
Kotlin,
Rust,
Go,
}
ProgramingLanguage.JS; // 1
ProgramingLanguage["Go"]; // 6
ProgramingLanguage[2]; // Java
또한 각 멤버에 명시적으로 값을 할당할 수 있고 일부 멤버에 값을 직접 할당하지 않아도
누락된 멤버를 이전 멤버 값의 숫자를 기준으로 1씩 늘려가며 자동으로 할당한다.
enum ProgramingLanguage {
TS = "TS",
JS = "JS",
Java = 300,
Python, // 301
Kotlin, // 302
Rust, // 303
Go, // 304
}
enum 타입은 주로 문자열 상수를 생성하는 데 사용된다. 이를 통해 응집력있는 집합 구조체를
만들 수 있으며, 사용자 입장에서도 간편하게 활용할 수 있다.
또한 그 자체로 변수 타입으로 지정할 수 있어 열거형을 타입으로 가지는 변수는 모든 멤버를
값으로 받을 수 있다. 이런 특성은 코드의 가독성을 높여준다.
enum ItemStatusType {
DELIVERY_HOLD = "DELIVERY_HOLD",
DELIVERY_READY = "DELIVERY_READY",
DELIVERING = "DELIVERING",
DELIVERED = "DELIVERED",
}
const checkItem = (itemStatus: ItemStatusType) => {
switch (itemStatus) {
case ItemStatusType.DELIVERY_HOLD:
case ItemStatusType.DELIVERY_READY:
case ItemStatusType.DELIVERING:
return false;
case ItemStatusType.DELIVERED:
default:
return true;
}
};
위 예제에서 itemStatus는 ItemStatusType 열거형을 타입으로 가져 다음과 같은 효과를 갖는다.
타입 안정성
열거형에 명시되지 않은 다른 문자열을 인자로 받을 수 없다.
명확한 의미 전달과 높은 응집력
열거형 타입이다루는 값이 무엇인지 명확하다.
가독성
응집도가 높기 때문에 말하고자 하는 바가 더욱 명확하다.
열거형을 사용할 때 주의해야 할 것이 있는데, 먼저 숫자로만 이루어져 있거나 타입스크립트가
자동으로 추론한 열거형은 안전하지 않은 결과를 낳을 수 있다.
enum은 역방향으로도 접근할 수 있는데, 할당된 값을 넘어서는 범위로 역방향으로 접근하더라도
타입스크립트는 막지 않는다. 이러한 동작을 막기 위해 const enum으로 열거형을 선언하는
방법이 있다. 이 방식은 역방향으로의 접근을 허용하지 않기 때문에 객체에 접근하는 것과 유사한
동작을 보장한다.
const enum Numbers {
zero,
one,
two,
three,
}
Numbers[0]; // X
const enum으로 선언한 문자/숫자 상수 열거형은 정의된 값 이외의 값을 허용하지 않아
의도하지 않은 값의 할당이나 접근을 방지하는데 도움이 된다.
이외에도 열거형의 가장 큰 문제는 따로 존재한다.
열거형은 타입/값 공간에서 모두 사용되며 자바스크립트 코드로 변환될 때 즉시 실행 함수 형식으로
변환된다. 이때 일부 번들러에서 트리쉐이킹 과정 중 이 값을 사용하지 않는 코드로 인식하지
못하는 경우가 발생해 불필요한 코드의 크기가 증가하는 결과를 초래할 수 있다.
이러한 문제를 해결하기 위해 앞서 언급했던 const enum 또는 as const assertion을 사용해
유니온 타입으로 열거형과 동일한 효과를 얻는 방법이 있다.
'TypeScript' 카테고리의 다른 글
우아한 타입스크립트 with 리액트 / 6장 타입스크립트 컴파일 (2) | 2024.12.12 |
---|---|
우아한 타입 스크립트 with 리액트 / 4장 타입 확장하기, 좁히기 (2) | 2024.11.29 |
우아한 타입스크립트 with 리액트 / 3장 고급타입 (2) (0) | 2024.11.21 |