객체 타입 정의 방법
익명 객체 타입
함수의 매개변수 등에 직접 객체 타입을 명시할 수 있습니다.
function logInfo(data: { title: string; count: number }): void {
console.log(`${data.title}: ${data.count}개`);
}
logInfo({ title: "책", count: 5 }); // 출력: 책: 5개
인터페이스 활용
재사용 가능한 객체 구조를 정의할 때 유용합니다.
interface Product {
name: string;
price: number;
}
const displayProduct = (prod: Product): string => `${prod.name} - ${prod.price}원`;
const item: Product = { name: "펜", price: 1000 };
console.log(displayProduct(item)); // 출력: 펜 - 1000원
타입 별칭 사용
객체 타입에 이름을 붙여 재사용성을 높입니다.
type Task = {
id: number;
description: string;
};
const addTask = (task: Task): void => {
console.log(`Task #${task.id}: ${task.description}`);
};
const task1: Task = { id: 1, description: "회의 준비" };
addTask(task1); // 출력: Task #1: 회의 준비
속성 수정자
선택적 속성
`?`를 사용해 속성을 필수에서 선택으로 변경합니다.
interface Settings {
theme?: string;
fontSize?: number;
}
function applySettings(options: Settings): string {
return `테마: ${options.theme ?? "기본"}, 크기: ${options.fontSize ?? 12}`;
}
console.log(applySettings({ theme: "다크" })); // 출력: 테마: 다크, 크기: 12
console.log(applySettings({})); // 출력: 테마: 기본, 크기: 12
strictNullChecks 옵션이 활성화된 경우, 선택적 속성은 암묵적으로 undefined를 포함한 타입으로 취급됩니다.
읽기 전용 속성
속성을 읽기 전용으로 만들어, 객체 생성 후 변경되지 않도록 할 수 있습니다. `readonly`로 속성 변경을 막습니다.
interface Account {
readonly accountId: string;
balance: number;
}
const updateBalance = (acc: Account, amount: number): void => {
acc.balance += amount;
// acc.accountId = "new"; // 오류: 읽기 전용
};
const myAccount: Account = { accountId: "A123", balance: 500 };
updateBalance(myAccount, 200);
console.log(myAccount.balance); // 출력: 700
읽기 전용 속성은 객체의 참조 자체는 불변하지만, 내부 값(예: 객체 속성의 프로퍼티)은 변경될 수 있습니다.
interface Account {
readonly account: {
id: string;
name: string;
}
balance: number;
}
const updateBalance = (acc: Account, amount: number): void => {
acc.balance += amount;
// acc.account = { id: "B123", name: "soo" }; // 오류: 읽기 전용
acc.account.name = "업데이트"
};
const myAccount: Account = { account: { id: "A123", name: "lee" }, balance: 500 };
updateBalance(myAccount, 200);
console.log(myAccount.account.name); // 출력: 업데이트
인덱스 시그니처
인덱스 시그니처를 사용하면, 미리 속성 이름을 알 수 없지만 모든 속성이 같은 타입을 가진 객체를 표현할 수 있습니다.
interface StringDictionary {
[key: string]: string;
}
const translations: StringDictionary = {
hello: "안녕하세요",
goodbye: "안녕히 가세요",
};
console.log(translations["hello"]); // 출력: 안녕하세요
인덱스 시그니처를 선언하면, 객체의 모든 프로퍼티가 지정한 타입을 만족해야 합니다. 만약 일부 속성의 타입이 다르다면, 해당 타입들을 유니온으로 지정할 수 있습니다.
interface FlexibleDictionary {
[key: string]: string | number;
version: number; // OK
appName: string; // OK
}
또한, 인덱스 시그니처에 readonly를 붙이면, 인덱스로 접근할 때 수정할 수 없도록 할 수 있습니다.
interface ReadonlyStringArray {
readonly [index: number]: string;
}
const greetings: ReadonlyStringArray = ["Hi", "Hello", "Bonjour"];
// greetings[0] = "Hey"; // 오류: 읽기 전용 인덱스
과잉 속성 검사
객체 리터럴을 사용할 때, 지정된 타입에 없는 속성을 전달하면 TypeScript가 오류를 발생시킵니다.
interface Profile {
name: string;
}
function saveProfile(profile: Profile): void {
console.log(profile.name);
}
// saveProfile({ name: "하영", age: 25 }); // 오류: age는 정의되지 않음
// 해결: 타입 단언
saveProfile({ name: "하영", age: 25 } as Profile);
타입 확장과 결합
인터페이스 확장
`extends`로 기존 인터페이스를 확장합니다.
interface Contact {
email: string;
}
interface Customer extends Contact {
orders: number;
}
const client: Customer = { email: "a@b.com", orders: 3 };
console.log(client.email); // 출력: a@b.com
인터섹션 타입
`&`로 여러 타입을 결합합니다.
type Info = { id: number };
type Status = { active: boolean };
type UserStatus = Info & Status;
const userState: UserStatus = { id: 1, active: true };
console.log(userState); // 출력: { id: 1, active: true }
제네릭 객체 타입
제네릭을 사용하면, 객체 타입을 보다 재사용 가능하고 유연하게 정의할 수 있습니다.
interface Container<T> {
value: T;
label: string;
}
const textContainer: Container<string> = { value: "안녕", label: "인사" };
const numContainer: Container<number> = { value: 42, label: "숫자" };
console.log(textContainer.value); // 출력: 안녕
console.log(numContainer.value); // 출력: 42
읽기 전용 배열과 튜플
ReadonlyArray
배열을 수정하지 못하도록 하기 위해 readonly 배열을 사용할 수 있습니다.
function listItems(items: readonly string[]): void {
console.log(items[0]);
// items.push("추가"); // 오류
}
listItems(["a", "b"]);
Tuple 타입
튜플은 고정된 개수와 순서로 서로 다른 타입의 요소들을 포함할 수 있는 배열 타입입니다.
type StringNumberPair = [string, number];
function printPair(pair: StringNumberPair): void {
const [text, num] = pair;
console.log(`Text: ${text}, Number: ${num}`);
}
printPair(["hello", 42]);
// printPair(["hello"]); // 오류: 요소 부족
// printPair(["hello", 42, true]); // 오류: 요소 초과
변경 불가능한 Tuple
튜플에 readonly를 붙여 변경 불가능한 튜플로 만들 수도 있습니다.
const point = [3, 4] as const; // readonly [3, 4]
// point[0] = 10; // 오류: 읽기 전용 튜플
'TypeScript' 카테고리의 다른 글
[TypeScript] keyof 타입 연산: 객체 키를 활용한 타입 정의 (0) | 2025.02.26 |
---|---|
[TypeScript] 재사용 가능한 컴포넌트 제네릭 만들기 (0) | 2025.02.26 |
[TypeScript] 함수 타입 정의하기 (0) | 2025.02.26 |
[TypeScript] 타입 좁히기(Narrowing): 타입을 안전하게 다루기 (1) | 2025.02.26 |
[TypeScript] 프로퍼티 데코레이터 사용하기 (0) | 2025.02.26 |