객체와 타입 정의
1. 객체와 타입 정의
1.1 객체와 타입스크립트
타입스크립트에서 {}
를 통해 객체를 생성하면 새로운 타입이 생성됩니다.
const obj = {
key: 'test',
};
const obj = {
key: 'test',
};
이때 obj의 타입은 { key: string }
으로 추론됩니다. 명시적으로 타입을 정의할 수도 있습니다.
let obj: { key: string };
let obj: { key: string };
1.2 type 키워드
타입 별칭(Type Alias)을 사용하면 반복되는 타입 정의를 재사용할 수 있습니다.
// Todo 타입 정의
type Todo = {
key: string;
todo: string;
};
// 타입 사용하기
function addTodo(newTodoData: Todo) {
// Todo 처리 로직
}
function editTodo(prevTodo: Todo): Todo {
// Todo 수정 로직
return editedTodo;
}
// Todo 타입 정의
type Todo = {
key: string;
todo: string;
};
// 타입 사용하기
function addTodo(newTodoData: Todo) {
// Todo 처리 로직
}
function editTodo(prevTodo: Todo): Todo {
// Todo 수정 로직
return editedTodo;
}
아래와 같이 type안에 type을 중첩하여 사용할 수도 있습니다.
type author = {
name: string;
email: string;
};
type notice = {
auth: author;
id: number;
title: string;
content: string;
};
const noticeData = {
auth: {
name: "licat",
email: "licat@weniv.co.kr"
},
id: 1,
title: "공지사항",
content: "안녕하세요. TypeScript 공부중입니다."
};
function printNoticeData(noticeData: notice) {
console.log(noticeData);
}
printNoticeData(noticeData);
type author = {
name: string;
email: string;
};
type notice = {
auth: author;
id: number;
title: string;
content: string;
};
const noticeData = {
auth: {
name: "licat",
email: "licat@weniv.co.kr"
},
id: 1,
title: "공지사항",
content: "안녕하세요. TypeScript 공부중입니다."
};
function printNoticeData(noticeData: notice) {
console.log(noticeData);
}
printNoticeData(noticeData);
1.2.1 선택적 속성
?
를 이용하여 선택적 속성을 정의할 수 있습니다.
type Todo = {
key: string;
todo: string;
caption?: string; // 선택적 속성
};
type Todo = {
key: string;
todo: string;
caption?: string; // 선택적 속성
};
1.2.2 타입 별칭의 다양한 사용
타입 별칭은 객체 타입뿐만 아니라 다른 타입에도 사용할 수 있습니다.
type Id = string;
type NumberOrString = number | string;
type Id = string;
type NumberOrString = number | string;
1.2.3 연산자를 이용한 타입 정의
|
와 &
연산자를 이용하여 유니온 타입과 인터섹션 타입을 정의할 수 있습니다.
-
유니온 타입(
|
): "or"A | B
는 "A 타입 또는 B 타입"이라는 의미입니다.- 예:
string | number
는 "문자열 또는 숫자"
-
인터섹션 타입(
&
): "and"A & B
는 "A 타입과 B 타입 모두"라는 의미입니다.- 예:
Character & Pet
은 "Character의 모든 속성과 Pet의 모든 속성을 다 가진 타입"
// 1. 유니온 타입 예제
type Score = number | string; // 점수는 숫자나 문자열로 표현할 수 있음
function printScore(score: Score) {
console.log(`점수: ${score}`);
}
printScore(100); // OK
printScore("A+"); // OK
printScore(true); // 에러! boolean은 Score 타입이 아님
// 2. 인터섹션 타입 예제
type Student = {
name: string;
grade: number;
};
type Athlete = {
sport: string;
level: number;
};
// 학생이면서 운동선수인 타입
type StudentAthlete = Student & Athlete;
const kim: StudentAthlete = {
name: "김철수", // Student 타입에서 필요
grade: 3, // Student 타입에서 필요
sport: "축구", // Athlete 타입에서 필요
level: 5 // Athlete 타입에서 필요
};
// 1. 유니온 타입 예제
type Score = number | string; // 점수는 숫자나 문자열로 표현할 수 있음
function printScore(score: Score) {
console.log(`점수: ${score}`);
}
printScore(100); // OK
printScore("A+"); // OK
printScore(true); // 에러! boolean은 Score 타입이 아님
// 2. 인터섹션 타입 예제
type Student = {
name: string;
grade: number;
};
type Athlete = {
sport: string;
level: number;
};
// 학생이면서 운동선수인 타입
type StudentAthlete = Student & Athlete;
const kim: StudentAthlete = {
name: "김철수", // Student 타입에서 필요
grade: 3, // Student 타입에서 필요
sport: "축구", // Athlete 타입에서 필요
level: 5 // Athlete 타입에서 필요
};
실제로 많이 사용되는 경우는 다음과 같습니다.
- 유니온(
|
): 여러 타입 중 하나를 선택할 때 (예: 숫자나 문자열로 된 ID) - 인터섹션(
&
): 여러 타입의 특성을 모두 합칠 때 (예: 회원이면서 관리자인 사용자)
아래처럼 함수에 프로퍼티를 추가하는 형태로도 사용할 수 있습니다.
type Student = {
name: string;
grade: number;
};
type Athlete = {
sport: string;
level: number;
};
// 학생이면서 운동선수인 타입
function printStudentAthlete(student: Student, athlete: Athlete) {
console.log(student);
console.log(athlete);
}
function printStudentAthlete2(student: Student & Athlete) {
console.log(student);
}
printStudentAthlete({ name: 'licat', grade: 3 }, { sport: 'soccer', level: 5 });
printStudentAthlete2({ name: 'licat', grade: 3, sport: 'soccer', level: 5 });
type Student = {
name: string;
grade: number;
};
type Athlete = {
sport: string;
level: number;
};
// 학생이면서 운동선수인 타입
function printStudentAthlete(student: Student, athlete: Athlete) {
console.log(student);
console.log(athlete);
}
function printStudentAthlete2(student: Student & Athlete) {
console.log(student);
}
printStudentAthlete({ name: 'licat', grade: 3 }, { sport: 'soccer', level: 5 });
printStudentAthlete2({ name: 'licat', grade: 3, sport: 'soccer', level: 5 });
1.2.4 읽기전용 속성
readonly
키워드로 읽기전용 속성을 정의할 수 있습니다.
type Todo = {
readonly key: string;
name: string;
};
const todo: Todo = {
key: "1",
name: "할 일 1"
};
// todo.key = "2"; // 에러! 읽기 전용 속성이므로 재할당 불가
todo.name = "할 일 2"; // OK
console.log(todo);
type Todo = {
readonly key: string;
name: string;
};
const todo: Todo = {
key: "1",
name: "할 일 1"
};
// todo.key = "2"; // 에러! 읽기 전용 속성이므로 재할당 불가
todo.name = "할 일 2"; // OK
console.log(todo);
1.2.5 구조적 타이핑
타입스크립트는 타입의 구조가 호환되면 같은 타입으로 취급합니다.
type Todo = { todo: string };
type TodoWithKey = { key: string; todo: string };
function processTodo(todo: Todo) {
console.log(todo.todo);
}
const extendedTodo: TodoWithKey = { key: '1', todo: '할 일' };
processTodo(extendedTodo); // 정상 작동
type Todo = { todo: string };
type TodoWithKey = { key: string; todo: string };
function processTodo(todo: Todo) {
console.log(todo.todo);
}
const extendedTodo: TodoWithKey = { key: '1', todo: '할 일' };
processTodo(extendedTodo); // 정상 작동
여기서 주의해야 할 점은 타입스크립트는 타입 호환성을 체크할 때 객체가 필요한 프로퍼티들을 "최소한" 가지고 있는지만 확인한다는 것입니다. 추가적인 프로퍼티가 있어도 문제되지 않습니다. 지금 todo 변수는 key도 가지고 있는 상태입니다. 쉽게 말해, "필요한 프로퍼티를 가지고 있다면, 그 타입으로 취급한다"라고 생각하면 됩니다.
type Person = {
name: string;
age: number;
};
type Developer = {
name: string;
age: number;
skills: string[];
};
let person: Person = { name: "김철수", age: 20 };
let developer: Developer = { name: "김영희", age: 25, skills: ["JavaScript", "TypeScript"] };
person = developer; // OK
console.log(person);
type Person = {
name: string;
age: number;
};
type Developer = {
name: string;
age: number;
skills: string[];
};
let person: Person = { name: "김철수", age: 20 };
let developer: Developer = { name: "김영희", age: 25, skills: ["JavaScript", "TypeScript"] };
person = developer; // OK
console.log(person);
2. 연습문제
-
다음 조건을 만족하는 타입을 정의해보세요.
- 사용자 정보를 담는
User
타입 - 필수 속성: id(숫자), name(문자열)
- 선택적 속성: email(문자열)
- id는 읽기전용으로 설정
- 사용자 정보를 담는
-
다음 두 타입을 정의하고 인터섹션 타입을 만들어보세요.
Product
: name(문자열), price(숫자) 속성Discount
: discountRate(숫자) 속성DiscountedProduct
: 위 두 타입의 인터섹션
3. 연습문제 정답
- 다음과 같이
User
타입을 정의할 수 있습니다.
// User 타입 정의
type User = {
readonly id: number;
name: string;
email?: string;
};
// User 정보를 출력하는 함수
function printUserInfo(user: User): void {
console.log("=== User Information ===");
console.log(`ID: ${user.id}`);
console.log(`Name: ${user.name}`);
if (user.email) {
console.log(`Email: ${user.email}`);
}
}
// 사용 예시
const user1: User = {
id: 1,
name: "Kim"
};
const user2: User = {
id: 2,
name: "Lee",
email: "lee@example.com"
};
printUserInfo(user1); // email 없는 경우
printUserInfo(user2); // email 있는 경우
// User 타입 정의
type User = {
readonly id: number;
name: string;
email?: string;
};
// User 정보를 출력하는 함수
function printUserInfo(user: User): void {
console.log("=== User Information ===");
console.log(`ID: ${user.id}`);
console.log(`Name: ${user.name}`);
if (user.email) {
console.log(`Email: ${user.email}`);
}
}
// 사용 예시
const user1: User = {
id: 1,
name: "Kim"
};
const user2: User = {
id: 2,
name: "Lee",
email: "lee@example.com"
};
printUserInfo(user1); // email 없는 경우
printUserInfo(user2); // email 있는 경우
- 다음과 같이
Product
,Discount
,DiscountedProduct
타입을 정의할 수 있습니다.
// Product 타입 정의
type Product = {
name: string;
price: number;
};
// Discount 타입 정의
type Discount = {
discountRate: number;
};
// Product와 Discount의 인터섹션 타입
type DiscountedProduct = Product & Discount;
// 할인된 상품 정보를 출력하는 함수
function printDiscountedProductInfo(product: DiscountedProduct): void {
const discountedPrice = product.price * (1 - product.discountRate);
console.log("=== Discounted Product Information ===");
console.log(`Name: ${product.name}`);
console.log(`Original Price: ${product.price.toLocaleString()}원`);
console.log(`Discount Rate: ${product.discountRate * 100}%`);
console.log(`Final Price: ${discountedPrice.toLocaleString()}원`);
}
// 사용 예시
const product: DiscountedProduct = {
name: "Laptop",
price: 1000000,
discountRate: 0.1
};
printDiscountedProductInfo(product);
// Product 타입 정의
type Product = {
name: string;
price: number;
};
// Discount 타입 정의
type Discount = {
discountRate: number;
};
// Product와 Discount의 인터섹션 타입
type DiscountedProduct = Product & Discount;
// 할인된 상품 정보를 출력하는 함수
function printDiscountedProductInfo(product: DiscountedProduct): void {
const discountedPrice = product.price * (1 - product.discountRate);
console.log("=== Discounted Product Information ===");
console.log(`Name: ${product.name}`);
console.log(`Original Price: ${product.price.toLocaleString()}원`);
console.log(`Discount Rate: ${product.discountRate * 100}%`);
console.log(`Final Price: ${discountedPrice.toLocaleString()}원`);
}
// 사용 예시
const product: DiscountedProduct = {
name: "Laptop",
price: 1000000,
discountRate: 0.1
};
printDiscountedProductInfo(product);