2024. 12. 15. 00:47ㆍProgramming Language/Node.js
이전에 main.ts에서 시작해보자.
이 포스트에서는 타입스크립트에서 어떤 종류의 타입을 사용할 수 있는지를 알아보도록 하자.
타입스크립트에서는 크게 기본타입, 복합타입, 특수타입, 사용자 정의 타입으로 분류된다.
기본타입(Primative Types)
TypeScript의 기본 타입은 JavaScript의 원시 타입(primitive types)에서 시작됐으며 변수에 저장할 수 있는 가장 작은 단위의 값을 표현한다.
이건 ECMAScript 사양에 정의된 원시데이터 유형과 타입스크립트에서 추가된 타입이 합쳐져 있다.
1. string
문자열 데이터를 나타낸다.
작은 따옴표('), 큰 따옴표("), 또는 백틱(`)으로 감쌀 수 있다.
let 변수명 : string = '문자열'; // '', 작은 따옴표를 사용
let 변수명 : string = "문자열"; // "", 큰 따옴표를 사용
let 변수명 : string = `문자열`; // ``, 백틱을 사용
백틱(`)으로 감싸는 경우에는 ${}를 사용해서 변수를 그 내부에 사용하는 것도 가능하다
예를 들면
이를 출력해보면
이렇게 변수를 사용한 값이 한번에 같이 출력되는 것을 확인할 수 있다.
2. number
타입스크립트에서는 별도로 int형 float형등 정수나 실수를 구분하지 않고 모든 숫자를 64비트 부동 소수점값을 사용한다.
또한 Infinity와 NaN이란 값을 지원하는데 Infinity는 무한대, 음의 무한대를 뜻하고 NaN는 숫자가 아님을 뜻한다.
사용의 예는
let age: number = 30; // 정수
let temperature: number = 36.6; // 부동소수점
let hex: number = 0x2a; // 16진수, 0x를 앞에 붙인 16진수를 입력하면 됨
let binary: number = 0b1010; // 2진수, 0b를 앞에 붙인 2진수를 입력하면 됨
let octal: number = 0o52; // 8진수, 0o를 앞에 붙인 8진수를 입력하면 됨
let infinity: number = Infinity; // 무한대
let notANumber: number = NaN; // 숫자가 아님
3. boolean
참(true), 거짓(false)값을 나타낸다.
let isDone: boolean = false
4. undefined
초기화되지 않은 변수의 값 또는 명시적으로 undefined로 값을 설정한다.
let notAssigned: undefined = undefined
5. null
값이 없음을 명시적으로 나타낸다.
let empty: null = null;
복합 타입 (Composite Types)
1. 객체 타입 (Object Types)
객체의 속성과 각 속성의 타입을 정의한다
객체의 원형은
let obj: { property1: 타입; property2: 타입; };
로 되어 있다
사용의 예제를 보면
let user: { name: string; age: number; active: boolean } = {
name: "Alice",
age: 25,
active: true,
};
와 같이 사용한다.
객체 내부의 속성이 선택적으로 존재한다면 ?를 사용해서
let user: { name: string; age?: number } = { name: "Bob" };
와 같이 사용한다.
객체 타입은 interface나 type으로 재사용 가능합니다
interface User {
name: string;
age?: number;
active: boolean;
}
let user: User = { name: "Alice", active: true };
2. 배열 타입 (Array Types)
배열의 요소가 특정 타입의 값을 가져야 할 때 사용한다.
배열의 원형은
let arr: 타입[];
// 또는
let arr: Array<타입>;
과 같이 구현하고 실사용의 예로는
let numbers: number[] = [1, 2, 3];
let strings: Array<string> = ["a", "b", "c"];
와 같이 사용한다.
3. 튜플 타입 (Tuple Types)
길이와 요소의 타입이 고정된 배열을 정의할때 사용하는 타입이다.
튜플의 원형은
let tuple: [타입1, 타입2, ...];
와 같이 구현된다.
실 사용의 예로는
let person: [string, number] = ["Alice", 25];
와 같이 구현한다.
튜플의 각 요소는 특정 타입을 가지며, 고정된 위치에 고정된 타입으로 된 값이 들어와야만 한다.
또한 객체와 비슷하게 선택적으로 요소를 지정할 수 도 있다.
let person: [string, number?] = ["Bob"];
그리고 튜플은 특이하게 Readonly 를 넣어서 수정이 불가능한 튜플로 생성할 수 도 있다.
let user: readonly [string, number] = ["Alice", 25];
// user[0] = "Bob"; // 오류: 읽기 전용
4. 유니온 타입 (Union Types)
변수가 둘 이상의 타입 중 하나를 가질 수 있도록 정의한다.
유니온 타입의 원형은
let variable: 타입1 | 타입2;
과 같이 구성된다.
실 사용의 예는
let id: number | string = 123;
id = "ABC123";
저렇게 id에는 number타입도 string 타입도 사용이 가능하다.
이 유니온 타입은 다른 타입에서도 잘 사용되는데
let union: (number|string)[] = ["Alice", 2, "Bob"];
과 같이 사용할 수도 있다.
그리고 union의 경우는 코드의 유연성을 높이지만, 각 타입에 명확한 동작을 위해서 타입 가드(Type Guard)를 사용해야 할 수 도 있다.
function printId(id: number | string) {
if (typeof id === "number") {
console.log("ID (number):", id);
} else {
console.log("ID (string):", id);
}
}
5. 인터섹션 타입 (Intersection Types)
여러 타입을 결합해서 하나의 타입으로 만든다.
인터섹션 타입은 모든 포함된 타입의 속성을 만족해야만 한다.
인터섹션 타입의 원형으로는
let variable: 타입1 & 타입2;
과 같이 사용한다.
type Person = { name: string };
type Employee = { employeeId: number };
type Developer = Person & Employee;
let dev: Developer = { name: "Alice", employeeId: 123 };
6. 리터럴 타입 (Literal Types)
값 자체를 타입으로 정의하며 특정한 값만을 허용한다.
리터럴 타입의 원형은
let variable: "값1" | "값2" | ...;
로 되어 있으며
let direction: "up" | "down" | "left" | "right";
direction = "up"; // 유효
// direction = "forward"; // 오류
와 같이 사용된다.
이렇게 선언했다면
이렇게 항목에 없는 값은 넣을 수 없다.
저 세가지 값 내에서만 사용가능하다.
이렇게 값 자체를 제한하는 것이 리터럴 타입이다.
이 리터럴 타입을 함수에서도 사용이 가능한데
이렇게 함수에 값을 제한해서 받아 올 수 도 있다.
이렇게 그 값이 아닌 값을 넣으면 어떤 값안에서 넣어야한다고 설명을 보여준다.
7. 타입 별칭 (Type Aliases)
복잡한 타입을 간단하게 표현하고 재사용할 수 있게 해주는 타입으로 type이란 키워드로 정의해서 사용이 가능하다.
타입 별칭의 원형은
type TypeName = 타입;
과 같이 사용이 가능하며
type Point = { x: number; y: number };
type ID = string | number;
let p: Point = { x: 10, y: 20 };
let id: ID = 123;
이렇게 사용이 가능하다.
특수 타입 종류
1. any 타입
모든 타입을 허용하는 타입으로, TypeScript의 타입 검사를 비활성화한다.
주로 타입을 알 수 없거나 동적으로 결정되는 값에 사용되며, TypeScript의 타입 안전성을 포기하는 결과를 초래할 수 있다.
any 타입의 값에는 모든 작업이 허용되나 런타임 오류는 방지하지 못한다.
any 타입의 원형은
let variable: any;
과 같이 생성하며
let value: any = 42;
value = "Hello"; // 다른 타입으로 변경 가능
value = true; // 또 다른 타입으로 변경 가능
과 같이 사용한다.
위와 같이 any 타입으로 설정하면 그냥 기존에 자바스크립트 처럼 어떤 타입의 값도 받아준다.
보통 타입스크립트에서는 any라는 타입을 잘 사용하지 않는게 좋다.
2. unknown
타입이 알려지지 않은 값으로, 안전한 타입 검사를 한다.
any의 대안으로, 동적 데이터를 다루면서도 타입 안정성을 유지한다.
unknown타입의 원형은
let variable: unknown;
으로 되어 있다.
그런데 unknown 타입은 모든 값을 할당할 수 있지만, 직접적인 조작은 불가능하다.
let value: unknown;
value = 5; // 유효
value = "Hello"; // 유효
value = { name: "John" }; // 유효
// value.toUpperCase(); // 오류: Object is of type 'unknown'
이렇게 모든 값에 할당은 가능 한데 변수에 담는 값이 문자라고 하더라도 string의 함수를 사용할 수는 없다.
이는 해당 변수의 타입은 string이 아니라 unknown이기 때문이다.
그렇기 때문에 타입검사를 통한 사용이 필요하다
let value: unknown = "Hello";
if (typeof value === "string") {
console.log(value.toUpperCase()); // 타입이 확인된 경우 안전하게 사용 가능
}
if (typeof value === "number") {
console.log(value.toFixed(2)); // 유효
}
// value.toUpperCase(); // 오류: 타입 확인 없이 직접 사용 불가
또한 타입단언(Type Assertion)을 사용해서 unknown타입을 특정 타입으로 변환할 수 있다.
let value: unknown = "Hello, World!";
let strLength: number = (value as string).length; // 유효
타입 단언(Type Assertion)
'as' 키워드를 사용하여 타입을 명시한다.
const name = 'Capt' as string;
이렇게 설정하면 타입스크립트 컴파일러는 특별히 타입을 체크하지도 않고 데이터의 구조도 신경쓰지 않는다.
그리고 실제로 타입을 변경하는건 아니고 타입 에러만 발생하지 않도록 한다
타입 단언을 과도하게 사용하면 타입 안정성이 떨어지고 유지보수가 어려워질 수 있기에 조심히 사용해야만 한다.
정리해보면, unknown에 문자, 숫자와 같은 데이터를 넣더라도 타입이 문자, 숫자가 아닌 unknown이기 때문에 다른 string타입 혹은 number타입에 대입할 수 도 함수를 사용할 수 도 없다.
3. never
절대로 발생하지 않는 값 또는 상태를 나타낸다
never 타입에는 어떤 값도 할당할 수 없다
이 타입은 도달할 수 없는 코드, 오류 처리 함수, 철저한 타입검사 등에 사용된다.
never 타입의 원형은
function functionName(): never;
와 같이 사용할 수 있으며
// #단순 타입에서 사용
let x: never;
// x에는 어떤 값도 할당할 수 없다
// #유니온에서의 사용
type A = string | number | never;
// A는 실질적으로 string | number과 같다
이 never타입은 타입을 촙히기 위해서 사용하기도 하는데
type Color = "red" | "blue" | "green";
이렇게 값을 Color라는 타입으로 세가지 타입을 설정해 두고 나서
let myColor: Color = "yellow" as any;
이렇게 Color 타입을 설정해두면 myColor에 red, blue, green만 담을 수 있지만 as any를 사용해서 yellow를 강제로 할당 시킨다.
// Color 타입에 없는 값이 할당되면 never 타입이 된다
if (myColor !== "red" && myColor !== "blue" && myColor !== "green") {
myColor; // 타입이 never
}
이렇게 모든 조건에 할당 되지 않으면 myColor라는 값이 어떤 값도 가질 수 없다고 판단하며 myColor가 never로 할당된다.
이는 타입스크립트의 컴파일러의 타입체커가 코드를 분석해서 조건문을 통과할때 해당 값이 어떤 값도 가질 수 없음을 판단하고 그 때 myColor에 never를 할당한다.
그래서 그 조건 문 내에서 myColor는 never가 되나 myColor가 외부에서도 never타입으로 유지되는건 아니고 조건문을 벗어나면 원래 타입 정보인 Color 타입을 그대로 사용한다.
이는 위에서 말했던 타입 단언을 사용했기 때문에 이 값의 타입을 신경 쓰지 마라고 설정한것과 동일하기에 yellow로 값이 할당되어 있으나 타입스크립트는 정적 타입 검사를 하기 때문에 인지하지 못한다.
그렇기에 컴파일러는 myColor를 Color 타입으로 취급한다.
(타입 단언을 사용하고 나서 myColor를 console로 출력하더라도 myColor는 Color 타입임을 any타입이 막아버려서 그냥 무관하게 yellow를 사용도 할당도 상관없다)
근데 never 타입은 함수에서 주로 사용되고 함수가 절대로 값을 반환하지 않거나, 무한 루프에 빠지거나 오류를 던지면 반환 타입으로 never를 사용한다
# 오류를 던지는 함수
function throwError(message: string): never {
throw new Error(message); // 이 함수는 값을 반환하지 않음
}
# 무한 루프에 빠지는 함수
function infiniteLoop(): never {
while (true) {
console.log("Running...");
}
}
4. void
반환 값이 없는 함수의 반환 타입을 나타낸다.
주로 값을 반환하지 않는 함수의 반환 타입으로 사용된다.
void 타입의 원형은
function functionName(): void;
와 같이 사용된다.
실 사용의 예로는
function logMessage(message: string): void {
console.log(message);
}
와 같이 사용할 수 있다.
void 타입의 경우는 undefined를 할당할 수 있다.
let noValue: void = undefined; // 이 경우 `undefined`는 `void` 타입에 할당 가능하다
03. 타입추론
타입 스크립트는 사실 타입 추론이란 기능이 있기에 매번 타입을 작성해야할 필요는 없다.
타입 추론(type inference)은 코드에서 명시적으로 타입을 선언하지 않아도, 컴파일러가 변수나 함수의 타입을 자동으로 추론하는 기능이다
타입스크립트는 코드 작성 시 값의 초기화나 컨텍스트(context) 에 따라 변수와 함수의 타입을 자동으로 결정한다.
변수를 선언하면서 값을 할당하면, 그 값을 기준으로 타입을 결정하고 함수나 메서드 호출, 반환값, 파라미터 등을 통해 타입을 유추한다.
let age = 30; // number로 추론
age = "hello"; // 오류: 'string'은 'number'에 할당할 수 없음
그러나 상황별로 타입을 추론하지 않는 경우가 있는데 함수 매개변수는 추론되지 않기에 함수의 매개변수는 명시적으로 타입을 지정해야 한다.
function greet(name) { // 오류 발생
return `Hello, ${name}`;
}
함수의 매개변수는 타입을 명확히 선언하지 않으면 any로 처리되어 버린다.
반대로 반환값의 경우는 함수 내부의 코드 흐름을 통해 타입을 추론한다.
'Programming Language > Node.js' 카테고리의 다른 글
TypeScript에 대한 간단한 정리 - 04. 타입 및 할당 단언(Assertions) (0) | 2024.12.16 |
---|---|
TypeScript에 대한 간단한 정리 - 01. 빠른 개발 환경 구성 (1) | 2024.12.14 |
Node.js 패키지 관리 (1) | 2024.12.14 |
Node.js의 모듈 시스템 (0) | 2024.12.10 |
Node.js의 내부 (0) | 2024.12.05 |