기본 타입
타입스크립트를 배우는 가장 중요한 목적 중 하나는 바로 타입(Type)을 활용하여 코드의 안정성과 가독성을 높이는 것입니다. 타입은 변수나 함수가 어떤 종류의 데이터를 다룰지 명확하게 정의하는 약속과 같습니다. 마치 우리가 물건을 담을 때 그 물건에 맞는 크기와 재질의 용기를 고르듯이, 코드에서도 데이터의 성격에 맞는 타입을 지정하는 것이죠.
이번 절에서는 타입스크립트에서 가장 기본적으로 제공하는 타입들을 하나씩 살펴보겠습니다. 이 기본 타입들은 여러분이 앞으로 작성하게 될 거의 모든 타입스크립트 코드의 근간이 될 것입니다.
숫자 (Number)
자바스크립트와 마찬가지로 타입스크립트의 숫자(Number) 타입은 정수와 부동소수점 숫자를 모두 포함합니다. 특별히 정수 타입이나 실수 타입이 따로 존재하지 않습니다. 모든 숫자는 64비트 부동소수점 형식으로 저장됩니다.
let decimal: number = 6; // 10진수
let hex: number = 0xf00d; // 16진수
let binary: number = 0b1010; // 2진수
let octal: number = 0o744; // 8진수
let float: number = 10.5; // 부동소수점
console.log(decimal); // 6
console.log(hex); // 61453
console.log(binary); // 10
console.log(octal); // 484
console.log(float); // 10.5
// 오류 예시: 문자열을 숫자에 할당할 수 없습니다.
// let notANumber: number = "hello"; // Type 'string' is not assignable to type 'number'.위 예시에서 볼 수 있듯이, 다양한 진법의 숫자 리터럴을 number 타입에 할당할 수 있습니다. 중요한 점은 number 타입으로 선언된 변수에는 오직 숫자 값만 할당할 수 있다는 것입니다.
문자열 (String)
문자열(String) 타입은 텍스트 데이터를 나타내는 데 사용됩니다. 자바스크립트와 동일하게 작은따옴표 ('), 큰따옴표 (") 또는 백틱 (`)을 사용하여 문자열을 정의할 수 있습니다. 백틱으로 정의하는 문자열은 템플릿 리터럴(Template Literals)이라고 불리며, 여러 줄에 걸쳐 문자열을 작성하거나 표현식을 삽입할 때 유용합니다.
let courseName: string = "TypeScript for Beginners";
let instructor: string = 'Kim Coding';
// 템플릿 리터럴 사용
let introduction: string = `Hello, my name is ${instructor}.
This course is about ${courseName}.`;
console.log(courseName); // TypeScript for Beginners
console.log(introduction);
// Hello, my name is Kim Coding.
// This course is about TypeScript for Beginners.
// 오류 예시: 숫자를 문자열에 할당할 수 없습니다.
// let notAString: string = 123; // Type 'number' is not assignable to type 'string'.템플릿 리터럴은 문자열 내부에 ${} 구문을 사용하여 변수나 JavaScript 표현식을 삽입할 수 있어, 동적인 문자열을 훨씬 깔끔하게 구성할 수 있도록 돕습니다.
불리언 (Boolean)
불리언(Boolean) 타입은 참(true) 또는 거짓(false) 두 가지 값만을 가질 수 있습니다. 조건문이나 논리 연산에 주로 사용됩니다.
let isCompleted: boolean = false;
let hasError: boolean = true;
if (isCompleted) {
console.log("작업이 완료되었습니다.");
} else {
console.log("작업이 진행 중입니다."); // 이 메시지가 출력됩니다.
}
// 오류 예시: 다른 타입을 불리언에 할당할 수 없습니다.
// let isValid: boolean = 1; // Type 'number' is not assignable to type 'boolean'.
// let isReady: boolean = "yes"; // Type 'string' is not assignable to type 'boolean'.불리언 타입은 코드의 논리 흐름을 제어하는 데 필수적이며, 타입스크립트 덕분에 true 또는 false가 아닌 다른 값이 할당되는 실수를 미리 방지할 수 있습니다.
배열 (Array)
기본 타입에서 타입 경계, 추론 결과, 런타임 영향을 정리한 것입니다.
배열은 여러 개의 값을 순서대로 저장하는 자료구조입니다. 타입스크립트에서 배열의 타입을 선언하는 방법은 두 가지가 있습니다.
요소 타입 뒤에 [] 사용:
가장 흔하게 사용되는 방법입니다. 배열이 포함할 요소들의 타입을 명시하고 그 뒤에 대괄호 []를 붙입니다.
let numbers: number[] = [1, 2, 3, 4, 5];
let fruits: string[] = ["apple", "banana", "cherry"];
// numbers.push("six"); // 오류: 'string' 형식의 인수는 'number' 형식의 매개 변수에 할당될 수 없습니다.
console.log(numbers[0]); // 1
console.log(fruits.length); // 3위 예시처럼 number[]는 이 배열이 오직 숫자 타입의 요소만을 가질 수 있음을 의미합니다. 다른 타입의 요소를 추가하려 하면 컴파일 시 오류가 발생합니다.
제네릭 배열 타입 (Array<ElementType>):
제네릭 문법을 사용하여 Array<요소타입> 형태로 배열 타입을 정의할 수 있습니다. 이는 좀 더 명시적인 방법이며, 제네릭에 익숙해지면 더욱 강력한 타입을 정의할 때 활용됩니다.
let numbersGeneric: Array<number> = [10, 20, 30];
let namesGeneric: Array<string> = ["Alice", "Bob", "Charlie"];
console.log(numbersGeneric[1]); // 20두 방법 모두 동일하게 배열의 타입을 정의하지만, 일반적으로 number[]와 같은 첫 번째 방식이 더 간결하여 많이 사용됩니다.
튜플 (Tuple)
튜플(Tuple)은 특정 개수의 요소 타입을 미리 정해놓고, 그 정해진 순서와 타입에 맞춰 값을 담을 수 있는 배열의 한 종류입니다. 배열은 요소의 개수나 타입 순서에 제약이 없지만, 튜플은 정해진 형태를 유지해야 합니다. 고정된 수의 요소와 각 요소의 타입이 중요할 때 유용합니다.
// [string, number]는 첫 번째 요소는 문자열, 두 번째 요소는 숫자여야 함을 의미합니다.
let userInfo: [string, number] = ["John Doe", 30];
let rgbColor: [number, number, number] = [255, 0, 0];
console.log(userInfo[0]); // John Doe
console.log(userInfo[1]); // 30
// 오류 예시: 순서나 타입이 맞지 않습니다.
// let invalidUser: [string, number] = [30, "John Doe"]; // Type 'number' is not assignable to type 'string'.
// let incompleteInfo: [string, number] = ["Jane Doe"]; // Property '1' is missing in type '[string]' but required in type '[string, number]'.
// 요소 추가는 허용되지만, 접근 시 타입 검사가 이루어집니다.
// userInfo.push(true); // 오류는 아니지만, 명확성을 위해 권장되지 않습니다. (튜플은 고정된 길이를 가정)
// userInfo[2]; // Property '2' does not exist on type '[string, number]'.튜플은 예를 들어 [경도, 위도]와 같이, 요소의 의미가 순서에 따라 명확하게 구분될 때 빛을 발합니다.
열거 (Enum)
열거(Enum)는 특정 값들의 집합에 이름을 부여하여, 코드의 가독성을 높이고 오류를 줄이는 데 사용됩니다. 예를 들어, 요일, 색상, 상태 코드 등과 같이 한정된 선택지를 표현할 때 유용합니다. 기본적으로 숫자 값을 가집니다.
// 숫자 열거 (Numeric Enum) - 기본값: 0부터 시작하여 1씩 증가
enum Direction {
Up, // 0
Down, // 1
Left, // 2
Right // 3
}
let userDirection: Direction = Direction.Up;
console.log(userDirection); // 0
console.log(Direction.Left); // 2
console.log(Direction[0]); // Up (역방향 매핑도 가능)
// 특정 숫자 값 할당 가능
enum StatusCode {
Success = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404
}
let responseStatus: StatusCode = StatusCode.Success;
console.log(responseStatus); // 200
console.log(StatusCode.NotFound); // 404
// 문자열 열거 (String Enum) - 각 멤버에 문자열 리터럴을 할당해야 합니다.
enum HttpStatus {
OK = "OK",
Created = "CREATED",
InternalServerError = "INTERNAL_SERVER_ERROR"
}
let serverStatus: HttpStatus = HttpStatus.OK;
console.log(serverStatus); // OK
console.log(HttpStatus.InternalServerError); // INTERNAL_SERVER_ERROR
// console.log(HttpStatus[0]); // 문자열 열거는 역방향 매핑을 지원하지 않습니다.열거형을 사용하면 하드코딩된 숫자나 문자열 대신 의미 있는 이름을 사용할 수 있어 코드가 훨씬 명확해집니다.
Any (아무거나)
any 타입은 타입 검사를 비활성화할 때 사용됩니다. 어떤 종류의 값이든 할당할 수 있으며, any 타입의 변수에 대해 어떤 프로퍼티나 메서드에 접근해도 타입 검사를 하지 않습니다. 이는 자바스크립트의 유연성을 그대로 가져오지만, 타입스크립트를 사용하는 이점을 포기하는 것이므로 꼭 필요한 경우에만 제한적으로 사용해야 합니다.
let unknownValue: any = 4;
unknownValue = "hello";
unknownValue = false;
// any 타입은 어떤 속성이나 메서드에도 접근을 허용합니다.
// 실제 런타임에 오류가 발생할 수 있으니 주의해야 합니다.
unknownValue.toFixed(2); // 숫자일 때는 가능
unknownValue.toUpperCase(); // 문자열일 때는 가능
unknownValue.noSuchMethod(); // 런타임 오류 발생 가능성이 있지만, 컴파일러는 허용합니다.
let someValue: any = "이것은 문자열입니다.";
let strLength: number = (someValue as string).length; // 타입 단언 (as 키워드)
console.log(strLength); // 13any는 주로 기존 자바스크립트 라이브러리를 사용할 때, 또는 데이터의 형태를 미리 알 수 없을 때 사용됩니다. 하지만 남용하면 타입스크립트를 사용하는 의미가 퇴색되므로 지양하는 것이 좋습니다.
Void (공허)
void 타입은 주로 함수가 어떤 값도 반환하지 않을 때 사용됩니다. 자바스크립트 함수에서 명시적으로 return 문이 없거나, return;만 있을 경우 해당 함수의 반환 타입은 void로 간주됩니다.
function warnUser(): void {
console.log("경고: 이 함수는 어떤 값도 반환하지 않습니다.");
}
let unusable: void = undefined; // void 타입에는 undefined만 할당 가능합니다.
// unusable = null; // strictNullChecks 옵션이 활성화된 경우 오류 (기본적으로는 가능)
warnUser(); // 함수 실행변수에 void 타입을 직접 할당하는 경우는 거의 없으며, 주로 함수의 반환 타입으로 사용됩니다.
Null과 Undefined
null과 undefined는 각각 자신의 이름을 타입으로 가집니다. 이들은 자바스크립트에서 "값이 없음"을 나타내는 특별한 값들입니다.
let u: undefined = undefined;
let n: null = null;
// 기본적으로 null과 undefined는 모든 다른 타입의 하위 타입입니다.
// 즉, number, string 등에 할당될 수 있습니다.
let num: number = undefined; // strictNullChecks가 false일 경우 허용 (기본값)
let str: string = null; // strictNullChecks가 false일 경우 허용
// 하지만 'strictNullChecks' 컴파일 옵션이 true일 경우,
// null과 undefined는 오직 void 또는 자신에게만 할당 가능합니다.
// 이 책에서는 'strictNullChecks: true'를 권장하며, 이는 더 엄격한 타입 검사를 가능하게 합니다.tsconfig.json 파일에 strictNullChecks: true 옵션을 설정하면 null과 undefined가 다른 타입에 할당되는 것을 엄격하게 제한하여 잠재적인 null 참조 오류를 방지할 수 있습니다. 이 책에서는 해당 옵션을 활성화하는 것을 권장합니다.
Never (절대)
never 타입은 절대 발생할 수 없는(도달할 수 없는) 타입을 나타냅니다. 주로 다음과 같은 경우에 사용됩니다.
- 함수가 항상 예외를 던지거나(throw),
- 함수가 절대 반환하지 않거나(무한 루프 등),
- 타입 가드(Type Guards)를 사용하여 모든 가능한 경우를 처리했음을 나타낼 때.
// 1. 항상 예외를 던지는 함수
function error(message: string): never {
throw new Error(message);
}
// 2. 무한 루프 함수
function infiniteLoop(): never {
while (true) {
// 이 함수는 절대 종료되지 않습니다.
}
}
// 3. 타입 가드에서 사용
declare function getWidget(): string | number; // 문자열 또는 숫자를 반환하는 가상의 함수
function processWidget(widget: string | number) {
if (typeof widget === "string") {
console.log("위젯은 문자열입니다.", widget.toUpperCase());
} else if (typeof widget === "number") {
console.log("위젯은 숫자입니다.", widget.toFixed(2));
} else {
// 이 코드는 절대 실행될 수 없어야 합니다.
// 만약 widget에 다른 타입이 추가된다면 컴파일러가 오류를 알려줍니다.
let _exhaustiveCheck: never = widget;
}
}never 타입은 타입스크립트의 타입 시스템에서 특정 코드 경로가 도달 불가능함을 명시적으로 알리는 역할을 합니다.
기본 타입을 실전 코드에 적용할 때는 값의 모양, 가능한 연산, 허용할 결측값, 타입 안전성의 강도를 함께 판단해야 합니다.
기본 타입을 고를 때 가장 자주 생기는 실수는 값의 범위, 빈 값 가능성, 컬렉션의 구조를 타입에 충분히 반영하지 않는 것입니다. 아래 다이어그램은 처음 타입을 붙이거나 리팩터링할 때 빠르게 확인할 점검 순서를 정리한 것입니다.
기본 타입을 실제 코드에 붙일 때는 타입 이름보다 값의 성격을 먼저 살펴보는 것이 좋습니다. 단일 값인지, 컬렉션인지, 결측 가능성이 있는지, 반환값이 없는 흐름인지에 따라 선택지가 달라집니다.
여기까지 타입스크립트의 기본 타입을 정리했습니다. 이 타입들은 애플리케이션의 데이터 구조를 표현하는 출발점이며, 값의 형태와 사용 가능한 연산을 제한하는 기준이 됩니다.
기본 타입에서는 타입 경계, 추론 범위, 호출부 영향이 어디에서 달라지는지 마지막으로 점검합니다.
아래 다이어그램은 TypeScript 기본 타입을 값의 형태와 사용 위치 기준으로 다시 분류합니다.