TypeScript를 사용하다 보면 객체의 구조를 정의할 때 가장 자주 사용하는 것이 바로 interface와 type입니다. 이 둘은 매우 유사하지만, 용도와 사용 방식에서 미묘한 차이가 있습니다. 이번 글에서는 interface와 type의 차이를 살펴보고, 어떻게 상속받거나 확장할 수 있는지 알아보겠습니다. 또한, Omit과 Pick 같은 유틸리티 타입을 통해 좀 더 유연하게 타입을 관리하는 방법을 배워보겠습니다.
1. interface와 type의 차이
interface란?
interface는 주로 객체의 구조를 정의할 때 사용합니다. 특히 객체 지향 프로그래밍 스타일에 익숙하다면, 상속을 통해 인터페이스를 확장하는 방식이 매우 자연스러울 것입니다.
interface Person {
name: string;
age: number;
}
interface Employee extends Person {
position: string;
}
const john: Employee = {
name: "John",
age: 30,
position: "Developer"
};
type이란?
type은 타입 별칭을 정의하는 도구입니다. type을 사용하면 단순히 객체의 구조뿐만 아니라 유니언, 튜플, 기타 복잡한 타입을 정의할 수 있습니다. interface와 다르게 직접적인 상속은 불가능하지만, 유니언(|)과 인터섹션(&)을 사용하여 타입을 확장할 수 있습니다.
type Person = {
name: string;
age: number;
};
type Employee = Person & {
position: string;
};
const jane: Employee = {
name: "Jane",
age: 28,
position: "Designer"
};
Employee는 Person 타입을 확장해 새로운 타입을 정의하고, position 속성을 추가합니다. & 연산자를 사용해 인터섹션 타입으로 타입을 결합할 수 있습니다.
2. interface와 type의 주요 차이점
특징interfacetype
확장 | 상속을 통해 확장 가능 | &(인터섹션) 또는 ` |
중복 선언 | 가능 (자동 병합됨) | 불가능 (중복 선언 시 오류 발생) |
사용 범위 | 주로 객체의 구조 정의 | 객체, 원시 타입, 유니언, 튜플 등 다양한 타입 정의 가능 |
유틸리티 타입과의 호환성 | Omit, Pick 등을 사용할 수 있음 | 마찬가지로 유틸리티 타입을 사용할 수 있음 |
3. Omit과 Pick을 활용한 타입 조작
Omit: 특정 속성 제외하기
Omit은 기존 타입에서 특정 속성을 제외하여 새로운 타입을 만들 때 사용합니다. 예를 들어, Person 타입에서 age 속성만 제외하고 싶다면 Omit을 사용할 수 있습니다.
type Person = {
name: string;
age: number;
address: string;
};
type PersonWithoutAge = Omit<Person, "age">;
const tom: PersonWithoutAge = {
name: "Tom",
address: "123 Street"
};
Pick: 특정 속성만 선택하기
반대로 Pick은 기존 타입에서 특정 속성만 선택하여 새로운 타입을 만들 때 사용됩니다. Person에서 name과 address만 선택하고 싶다면 다음과 같이 사용할 수 있습니다.
type Person = {
name: string;
age: number;
address: string;
};
type PersonWithNameAndAddress = Pick<Person, "name" | "address">;
const anna: PersonWithNameAndAddress = {
name: "Anna",
address: "456 Avenue"
};
실전 예시: 사용자 데이터 관리
기본 사용자 타입 정의
예를 들어, 우리가 사용자 데이터를 관리하는 애플리케이션을 만든다고 가정해보겠습니다. 이때, 각 사용자의 정보를 표현하기 위해 기본적인 User 타입을 정의할 수 있습니다.
type User = {
id: number;
name: string;
email: string;
password: string;
address: string;
phone: string;
role: 'admin' | 'user';
};
이 타입은 사용자마다 고유한 id, name, email, password, address, phone, 그리고 사용자 권한인 role을 포함하고 있습니다.
예시 1: Omit을 사용하여 비밀번호 제거하기
서버에서 사용자 데이터를 클라이언트로 전송할 때 보안상의 이유로 **비밀번호(password)**를 포함하지 않으려면, Omit을 사용하여 비밀번호를 제거한 타입을 만들 수 있습니다.
// User 타입에서 password를 제외한 새로운 타입
type PublicUser = Omit<User, 'password'>;
const publicUser: PublicUser = {
id: 1,
name: "Alice",
email: "alice@example.com",
address: "123 Wonderland Ave",
phone: "555-1234",
role: 'user'
};
PublicUser는 User에서 비밀번호를 제외한 모든 속성을 가진 타입입니다. 이제 클라이언트에게 전송할 때는 이 타입을 사용하여 비밀번호 유출을 방지할 수 있습니다.
예시 2: Pick을 사용하여 필수 정보만 선택하기
때로는 사용자 목록을 관리할 때 모든 정보가 필요하지 않을 수 있습니다. 예를 들어, 사용자 목록에서 기본적인 정보(이름, 이메일, 전화번호)만 표시하려면, Pick을 사용해 필요한 속성만 선택할 수 있습니다.
// User 타입에서 이름, 이메일, 전화번호만 선택한 타입
type BasicUserInfo = Pick<User, 'name' | 'email' | 'phone'>;
const basicUserInfo: BasicUserInfo = {
name: "Bob",
email: "bob@example.com",
phone: "555-5678"
};
BasicUserInfo 타입은 사용자 목록에 표시할 때 필요한 정보만 포함합니다. 이렇게 필요한 정보만 선택해서 처리하면 불필요한 데이터를 제거하여 성능을 최적화할 수 있습니다.
추가 예시: 관리자 데이터를 위한 타입 확장
관리자(admin)는 일반 사용자와 달리 추가적인 권한이 필요합니다. 예를 들어, 관리자는 다른 사용자를 생성, 수정, 삭제할 수 있는 권한이 있어야 합니다. 이를 위해, User 타입을 확장해 새로운 Admin 타입을 정의해보겠습니다.
type Admin = User & {
permissions: string[];
};
이때, Admin 타입은 기존 User 타입을 확장하여 추가적인 permissions 배열을 포함하게 됩니다. 이제 각 관리자는 특정 권한을 가진 리스트를 가질 수 있습니다.
const adminUser: Admin = {
id: 2,
name: "Carol",
email: "carol@example.com",
password: "secret123",
address: "456 Tech Blvd",
phone: "555-7890",
role: 'admin',
permissions: ["create", "edit", "delete"]
};
이렇게 새로운 타입을 확장하거나 조합하여 다양한 사용자 역할에 따라 필요한 데이터를 관리할 수 있습니다.
요약
- Omit은 객체 타입에서 특정 속성을 제외할 때 유용하며, 예를 들어 비밀번호와 같은 민감한 데이터를 처리하지 않으려면 사용할 수 있습니다.
- Pick은 객체 타입에서 특정 속성만 선택하여 필요한 정보만 남길 때 유용합니다. 사용자 목록에서 최소한의 정보만 보여줄 때 사용할 수 있습니다.
- 타입 확장을 통해 User 타입을 확장해 관리자 등 특정 역할에 맞춘 추가적인 속성을 정의할 수 있습니다.
Omit과 Pick은 객체 타입을 관리하고 확장할 때 매우 유용한 도구입니다. 이를 통해 코드를 더욱 간결하고 안전하게 작성할 수 있습니다.
'Programming Language > JS & TS' 카테고리의 다른 글
[TS] Type Guard 와 as 키워드 (0) | 2024.10.31 |
---|---|
[JS] every 메소드로 객체 속 값 비교하기 (0) | 2024.10.22 |
[JS] Prototype과 __proto__ (1) | 2024.10.17 |
event.preventDefault & event stopPropagation (0) | 2024.10.10 |
History 관리(Command 패턴 & Deque 자료구조 & Factory Method 패턴) (1) | 2024.10.09 |