2023년 3월 16일 목요일

TypeScript의 여러 데이타 타입들

 

TypeScript의 여러 데이타 타입들

TypeScript는 number, string, boolean 등의 기본 데이타 타입 이외에 아래와 같은 데이타 타입들을 지원한다.

any 타입

any 타입은 어떠한 데이타 값이라도 받아들일 수 있는 타입이다. any 타입의 변수에는 문자열을 할당했다가 다시 숫자, 부울린 값을 할당할 수도 있다. any 타입은 기본적으로 컴파일시에 타입 체킹을 하지 않는데, 이러한 측면에서 object 타입과 유사하다. 단, object 타입은 값을 할당할 수만 있고, 비록 그 object 객체가 메서드를 가지고 있을지라도 메서드를 호출할 수는 없는 반면, any 타입은 값 할당 뿐만 아니라 메서드를 호출할 수도 있다. any 타입의 메서드 호출은 컴파일시에 타입 체킹을 하지 않고, 런타임시에 호출하기 때문에 만약 메서드가 없다면 런타임시에 호출에 실패하게 된다.

1
2
3
4
5
6
7
8
// any는 여러 타입 가능
let unknown: any = 1;
unknown = true;
unknown = "Hello";
 
// any는 메서드 호출 가능
let s = unknown.substring(1, 4);
console.log(s); // "ell" 출력
object 타입

object 타입은 Primitive 타입이 아닌 Non-primitive 타입을 가리키는 타입이다. Primitive 타입은 string, number, boolean, bigint, symbol, null, undefined를 가리키는데, 이외의 다른 모든 타입들은 Non-primitive 타입으로 취급된다.

object 타입은 Non-primitive 타입만을 가지므로, object 타입의 변수 혹은 파라미터에는 Primitive 타입의 값을 할당하거나 전달할 수 없다. 예를 들어, 아래 예제에서 create() 함수는 object 타입의 파라미터를 가지므로, 문자열이나 숫자를 파라미터로 전달할 수 없다.

1
2
3
4
5
6
7
8
9
10
declare function create(o: object): void;
 
// Non-primitive 타입 전달
create({id: 1});
 
// 에러: primitive 타입 전달
//   Argument of type '"Tom"' is not assignable
//   to parameter of type 'object'
create("Tom");
create(123);

여기서 한가지 주의할 것은 TypeScript의 "object" 타입(첫문자가 소문자임)은 "Object" 타입(첫문자가 대문자임)과 다른 것으로, Object는 interface 타입으로 모든 JavaScript 객체들에게 공통된 인터페이스를 가리킨다. 예를 들어, Object 인터페이스는 toString(), valueOf(), isPrototypeOf(), hasOwnProperty() 등과 같은 메서드를 갖는다. Object 타입으로 정의된 변수에는 모든 JavaScript 객체를 넣을 수 있으므로, 예를 들어, 문자열, 숫자, 부울린, 혹은 다른 JavaScript 객체 등을 할당할 수 있다.

1
2
3
4
5
let o: Object;
o = "Hello";
o = 123;
let s = o.toString();
console.log(s);
void 타입

void 타입은 어떠한 타입도 가지지 않는 것을 의미하는 것으로, 일반적으로 함수에서 리턴값이 없을 경우 void 를 사용한다. void 타입의 변수가 정의되었다면, 이 변수에는 undefined 혹은 null 만 할당될 수 있다. 하지만, Void 타입의 변수는 보통 큰 의미가 없기 때문에, 통상적으로 정의하지 않는다.

1
2
3
4
5
6
7
function log(msg): void {
    console.log(msg);
}
 
let noReturn: void = log("error");
// "undefined" 출력됨
console.log(noReturn);
never 타입

never 타입은 주로 함수의 리턴타입으로 사용되는데, 함수가 항상 Exception을 throw 하거나 함수 내에 무한루프 같은 것이 있어 절대 리턴하지 않는 경우 사용된다.

1
2
3
4
5
function error(msg) : never {
    throw new Error(msg);
}
 
error("Critical error");

함수가 항상 끝까지 실행되지 못하는 상황, 예를 들어 중간에 무한루프가 있는 경우, never를 사용한다. 아래 코드를 실행하면 Ctrl+C 를 눌러 무한루프를 빠져나와야 한다.

1
2
3
4
5
6
function loop(): never {
    while (true) {
    }
}
 
loop();
Union 타입

Union 타입은 여러 타입들을 OR (|)으로 묶어서 사용하는 것으로, 지정된 각 타입들 중 하나를 사용할 수 있는 타입이다. 예를 들어, 아래 예제에서 add() 함수의 파라미터 a, b 는 모두 number | string 으로 지정되어 있는데, 이 파라미터에는 number 타입 혹은 string 타입을 넣을 수 있다는 의미이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// Union 타입: number | string
function add(a: number | string, b: number | string) {
    if (typeof a === "number" && typeof b === "number") {
        return a + b;
    } else {
        return a.toString() + b.toString();
    }
}
 
let result: any = add(2, 3);  // 5 출력
console.log(result);
result = add("James", "Lee");  // "JamesLee" 출력
console.log(result);
Type Alias (type 문)

TypeScript는 타입에 별명을 붙이는 Type Alias를 지원한다 (JavaScript에는 없는 기능). Type Alias는 type 문을 사용하는데, 예를 들어 위 Union 타입 예제에 있는 입력 파라미터를 아래와 같이 type문을 써서 변경할 수 있다. 즉, type문을 사용하여 number | string 타입에 대해 AddParam이라는 별명(alias)을 생성한 것이다.

1
2
3
type AddParam = number | string;
 
function add(a: AddParam, b: AddParam) {...}

type문은 기본 타입들에 대한 alias 이외에 함수, 제네릭 등 다양한 타입들에 대해 사용될 수 있다. 아래는 type문을 사용한 몇가지 경우를 예시한 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 함수에 대한 type alias
type AddFunc = (a: number, b: number) => number;
 
// 제네릭을 사용한 type alias
type TreeNode<T> = {
    data: T;
    left: TreeNode<T>;
    right: TreeNode<T>;
};
 
let root: TreeNode<number> = {
    data: 1,
    left: null,
    right: null,
};
 
// 리터럴들에 대한 type alias
type Confirm = "Yes" | "No" | "Cancel";

댓글 없음:

댓글 쓰기