객체 타입(Object Types)
TypeScript에서 Object Types는 다양한 형태의 객체를 나타내기 위한 타입이다.
다음은 TypeScript에서 제공하는 Object Types의 종류다.
- Object
- Array
- Tuple
- Function
- Class
- Void
- Never
- Enum
- Union
- Intersection
이러한 Object Types를 적절히 조합하여 다양한 데이터 타입을 정의할 수 있다.
Object
TypeScript에서 object 타입은 JavaScript 객체를 나타내는 타입이다. object 타입은 다른 객체 타입을 포함하여 모든 객체 유형에 대한 상위 유형이다.
예를 들어, 다음 코드에서는 object 타입의 변수 person을 선언하고 객체 리터럴을 할당한다.
let person: object = { name: "John", age: 30 };
이 코드에서 person은 object 타입이므로 어떤 객체라도 할당할 수 있다.
하지만 object 타입에는 객체의 속성과 유형 정보가 없기 때문에 속성에 대한 정보를 추가하려면 타입을 구체화해야 한다.
예를 들어, 다음 코드에서는 name 속성과 age 속성이 있는 Person 인터페이스를 정의하고, Person 타입의 변수 person을 선언하고 객체 리터럴을 할당한다.
interface Person {
name: string;
age: number;
}
let person: Person = { name: "John", age: 30 };
이제 person 변수의 속성과 유형 정보가 정의되어 있으므로 name 속성과 age 속성에 대해 타입 검사가 수행된다.
object 타입은 다음과 같은 경우 유용하다.
- 객체의 모든 유형에 대해 일반적인 상위 유형이 필요한 경우
- 객체의 유형이 동적이거나 미리 알 수 없는 경우
하지만 대부분의 경우, object 타입보다는 보다 구체적인 객체 타입을 사용하는 것이 좋다.
Array
TypeScript에서 array 타입은 배열을 나타내는 타입이다. 배열은 일련의 값으로 구성된 순서화된 컬렉션이다.
예를 들어, 다음 코드에서는 number 타입의 값을 가진 배열을 선언하고 할당한다.
let numbers: number[] = [1, 2, 3, 4, 5];
이 코드에서 numbers 변수는 number 타입의 값으로 구성된 배열을 나타내는 것으로 타입이 지정된다.
TypeScript에서 배열은 다양한 방법으로 정의할 수 있다. 배열을 정의하는 방법에는 다음과 같은 방법이 있다.
- number[] 형태의 배열 타입 표기법
- 제네릭 배열 타입 Array<number>
- Array<number>의 축약형 표기법인 number[]
다음은 위에서 언급한 방법 중 하나인 제네릭 배열 타입 Array<number>을 사용한 예시다.
let numbers: Array<number> = [1, 2, 3, 4, 5];
이 코드는 이전 코드와 동일하게 동작한다.
배열에는 다양한 메서드가 있으며, 이를 사용하여 배열을 조작하고 수정할 수 있다. 예를 들어, push() 메서드를 사용하여 배열의 끝에 새로운 값을 추가할 수 있다:
numbers.push(6);
Tuple
TypeScript의 Object Types 중 Tuple은 고정된 요소 수를 가지며 각 요소의 유형이 미리 정의된 배열이다.
예를 들어, [string, number, boolean]은 문자열, 숫자 및 부울 값을 순서대로 포함하는 Tuple이다.
Tuple의 각 요소는 대괄호 []를 사용하여 액세스된다.
let myTuple: [string, number, boolean];
myTuple = ["Hello", 123, true];
console.log(myTuple[0]); // "Hello"
console.log(myTuple[1]); // 123
console.log(myTuple[2]); // true
Tuple은 고정된 크기를 갖기 때문에 새로운 요소를 추가하거나 삭제할 수 없다.
Tuple의 요소를 초기화할 때는, Tuple의 타입 정의와 실제 값의 유형이 일치해야 한다.
Tuple 타입 정의에서 요소의 순서는 매우 중요하다. 예를 들어, [string, number, boolean]과 [number, string, boolean]은 서로 다른 Tuple이다.
Tuple은 다음과 같은 유형을 가지는 변수에 많이 사용된다.
let tupleVariable: [string, number] = ["Hello", 123];
Tuple을 사용하면 일부 함수의 인수 또는 반환 값으로 복수 개의 값을 전달할 수 있다.
function returnTuple(): [string, number] {
return ["Hello", 123];
}
let myTuple: [string, number] = returnTuple();
Tuple은 TypeScript의 강력한 유형 중 하나이며, 고정된 요소 수가 필요한 경우 매우 유용하다.
Function
TypeScript의 Object Types 중 하나인 함수(Function)는 다른 유형의 객체와 마찬가지로 TypeScript에서 강력한 유형의 기능을 제공한다. 함수 유형은 함수의 매개 변수 및 반환 값의 유형을 지정할 수 있으므로 코드의 가독성과 안정성을 향상시키는 데 도움이 된다.
함수 유형은 다음과 같은 구문을 사용하여 정의할 수 있다.
(parameter1: type, parameter2: type, ...) => returnType
위의 구문에서 parameter1, parameter2 및 ...은 함수에 전달되는 매개 변수를 나타내며, type은 매개 변수의 유형을 지정한다. returnType은 함수가 반환하는 값의 유형을 지정한다.
예를 들어, 다음은 문자열과 숫자를 인수로 사용하여 숫자를 반환하는 함수 유형을 정의한다.
(typeScriptFunc: string, typeScriptVersion: number) => number
함수 유형은 다른 변수와 마찬가지로 변수에 할당하거나 함수 매개 변수로 전달할 수 있다. 예를 들어, 다음은 myFunc 변수에 함수 유형을 할당한다.
let myFunc: (typeScriptFunc: string, typeScriptVersion: number) => number;
함수 유형은 일부 TypeScript 함수에서 인수 및 반환 값의 유형을 검증하는 데 사용된다. 이를 통해 코드의 안정성이 향상되며 디버깅 시간이 단축된다.
예를 들어, 다음은 add 함수의 두 개의 숫자 매개 변수가 전달되는 경우 합계를 반환하는 함수를 정의하는 TypeScript 코드다.
function add(num1: number, num2: number): number {
return num1 + num2;
}
위의 코드에서 add 함수는 두 개의 number 매개 변수를 사용하고 number를 반환한다. 이를 통해 코드 사용자가 함수가 예상대로 작동하는지 쉽게 확인할 수 있다.
Class
TypeScript의 클래스(Class)는 JavaScript의 클래스와 비슷한 구조를 가지며, TypeScript의 고유한 기능과 기능을 추가한 것이다. 클래스는 TypeScript에서 객체 지향 프로그래밍을 구현하는 데 사용된다. 클래스를 사용하여 객체를 생성하고 객체의 동작을 정의하면 코드의 가독성과 유지 보수성이 향상된다.
또한 상속, 추상 클래스, 인터페이스 구현과 같은 기능을 사용하여 객체 지향 프로그래밍의 다양한 개념을 적용할 수 있다.
TypeScript에서 클래스는 다음과 같은 구문으로 작성된다.
class className {
// class members
}
위의 구문에서 className은 클래스의 이름이다. 클래스 멤버는 클래스 내부에 선언되며, 일반적으로 속성(properties)과 메서드(methods)로 구성된다.
TypeScript 클래스는 다음과 같은 특징을 가지고 있다.
- 상속: TypeScript 클래스는 상속을 지원한다. 클래스는 extends 키워드를 사용하여 다른 클래스를 상속할 수 있다.
- 접근 제한자: TypeScript 클래스는 public, private, protected와 같은 접근 제한자를 사용하여 클래스 멤버에 대한 접근을 제한할 수 있다.
- 생성자: TypeScript 클래스는 생성자를 사용하여 클래스의 인스턴스를 초기화할 수 있다. 생성자는 constructor 키워드를 사용하여 정의된다.
- 추상 클래스: TypeScript 클래스는 추상 클래스를 지원한다. 추상 클래스는 구현을 제공하지 않는 추상 메서드를 포함할 수 있다.
- 인터페이스 구현: TypeScript 클래스는 인터페이스를 구현할 수 있다. 클래스는 implements 키워드를 사용하여 인터페이스를 구현한다.
다음은 TypeScript에서 클래스를 사용하여 생성한 간단한 예제이다.
class Person {
private name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
public getAge(): number {
return this.age;
}
public getName(): string {
return this.name;
}
}
let person1 = new Person("Alice", 30);
console.log(person1.getName()); // "Alice"
console.log(person1.getAge()); // 30
위의 예제에서 Person 클래스는 name 및 age 두 개의 속성과 getAge() 및 getName() 두 개의 메서드를 가지고 있다. 생성자는 name과 age 매개 변수를 받아 클래스의 속성을 초기화한다.
person1 객체를 생성하여 getName()과 getAge() 메서드를 호출하면 속성 값이 반환된다. 클래스 멤버에 접근 제한자를 사용하여 name과 age 속성에 대한 접근을 제한하고 있다. 따라서 클래스 외부에서는 name과 age에 직접 접근할 수 없다.
Void
TypeScript에서 void는 함수의 반환 타입으로 사용되며, 해당 함수가 값을 반환하지 않음을 나타낸다.
즉, 함수가 실행되고 작업이 수행되지만 값을 반환하지 않는 경우 void 타입을 사용한다.
예를 들어, 다음은 printHello() 함수를 정의하고 반환 타입으로 void를 사용한 예시다.
function printHello(): void {
console.log("Hello!");
}
위의 코드에서 printHello() 함수는 인자를 받지 않고 console.log를 사용하여 문자열 "Hello!"를 출력한다. 반환 타입으로 void를 사용하였으므로, 이 함수는 어떤 값도 반환하지 않는다.
void 타입은 함수의 반환 타입으로만 사용할 수 있다. 변수나 상수에 대한 타입으로는 사용할 수 없다. void 타입은 undefined와 유사하게 동작하지만, undefined는 변수에 할당할 수 있는 값이며, void는 함수의 반환 타입으로만 사용된다.
void 타입은 함수가 값을 반환하지 않음을 명시적으로 나타내는 데 사용된다. 반환 값을 무시할 수 있는 경우, void 타입을 사용하여 함수의 반환 값을 명시적으로 무시할 수 있다. 예를 들어, 다음은 doSomething() 함수를 호출하고 반환 값을 무시하는 예시다.
function doSomething(): void {
// do something
}
const result = doSomething(); // result는 undefined 타입이다.
위의 예시에서 doSomething() 함수는 void 타입으로 반환되므로, result 변수에는 undefined 값이 할당된다.
이러한 방식으로 void 타입은 TypeScript에서 함수의 반환 값을 나타내는 데 사용된다.
Never
TypeScript에서 never는 다른 모든 타입의 하위 타입이다. 즉, 모든 타입은 never 타입을 할당할 수 있다.
never 타입은 함수의 반환 타입이나 변수의 타입으로 사용될 수 있으며, 해당 함수나 변수가 도달할 수 없는 코드를 가지고 있는 경우에 해당한다. 다시 말해, never 타입은 어떤 값도 가질 수 없는 타입이다.
예를 들어, 다음은 throwError() 함수를 정의하고 반환 타입으로 never를 사용한 예시다.
function throwError(message: string): never {
throw new Error(message);
}
위의 코드에서 throwError() 함수는 인자로 받은 문자열을 사용하여 Error 객체를 생성하고 던진다. 이 함수는 항상 예외를 던지므로, 호출한 쪽에서는 어떠한 값을 반환받을 수 없다. 이 때문에 never 타입이 함수의 반환 타입으로 사용된다.
또 다른 예로는, 다음과 같이 무한 루프를 돌면서 코드를 실행하는 neverEnding() 함수가 있다.
function neverEnding(): never {
while (true) {
// do something
}
}
위의 코드에서 neverEnding() 함수는 항상 무한 루프를 돌면서 실행되므로, 호출한 쪽에서는 이 함수가 반환할 값을 기대할 수 없다. 이 때문에 never 타입이 함수의 반환 타입으로 사용된다.
never 타입은 코드의 안정성을 높이는 데 사용된다. 예를 들어, switch 문에서 모든 경우를 다루는 것이 중요하며, 모든 경우를 다루지 않으면 never 타입을 반환하는 default문을 사용하여 컴파일러에서 경고를 발생시킬 수 있다. 이를 통해 프로그램의 오류를 사전에 방지할 수 있다.
이러한 방식으로 never 타입은 TypeScript에서 함수나 변수의 반환 값을 나타내는 데 사용된다.
Enum
TypeScript에서 Enum(열거형)타입은 숫자 또는 문자열 값을 가지는 열거형 멤버를 정의하는 방법을 제공한다. 열거형 멤버는 이름과 값을 가지며, 값은 명시적으로 설정하지 않으면 자동으로 증가하는 값을 가진다.
다음은 TypeScript에서 열거형 타입을 정의하는 방법이다.
enum Color {
Red,
Green,
Blue,
}
위 코드에서 Color는 열거형의 이름이며, Red, Green, Blue는 열거형 멤버이다.열거형 멤버는 각각 0, 1, 2와 같은 숫자 값이 자동으로 할당된다.
따라서 Color.Red는 0, Color.Green은 1, Color.Blue는 2와 같은 값을 가지게 된다.
값이 명시적으로 설정된 열거형 멤버는 다음과 같이 정의할 수 있다.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
위 코드에서 Direction은 열거형의 이름이며, Up, Down, Left, Right는 열거형 멤버이다. 각 멤버는 문자열 값을 가지며, 각 멤버에는 값을 명시적으로 할당할 수 있다.
열거형은 keyof 연산자와 함께 사용하여 타입 안정성을 보장하는 데에도 사용될 수 있다. 예를 들어, 다음과 같이 keyof 연산자와 함께 열거형을 사용하여 인터페이스의 속성을 검사할 수 있다.
interface Person {
name: string;
age: number;
gender: Color;
}
function printProperty(person: Person, key: keyof Person) {
console.log(`${key}: ${person[key]}`);
}
const person = { name: "John", age: 30, gender: Color.Blue };
printProperty(person, "name"); // "name: John"
printProperty(person, "age"); // "age: 30"
printProperty(person, "gender"); // "gender: 2"
위 코드에서 Color 열거형을 사용하여 Person 인터페이스의 gender 속성을 검사할 수 있다. 이를 통해 타입 안정성을 보장할 수 있다.