교차타입 : & 기호를 사용하여 여러 타입을 하나로 결합하는 타입
문법: TypeA & TypeB & TypeC ..
1. 기본적인 속성 결합
interface Identifiable { id: number; }
interface Timestamped {
createdAt: Date;
updatedAt: Date;
}
// Identifiable 타입과 Timestamped 타입을 교차하여 새로운 타입을 생성
type DataWithTimestamp = Identifiable & Timestamped;
// DataWithTimestamp 타입의 객체는 id, createdAt, updatedAt 속성을 모두 가져야 합니다.
const myData: DataWithTimestamp = {
id: 123,
createdAt: new Date(),
updatedAt: new Date(),
// id, createdAt, updatedAt 중 하나라도 없으면 타입 에러 발생
};
console.log(myData.id);
console.log(myData.createdAt);
console.log(myData.updatedAt);
2. 동일한 이름의 속성 처리
- 동일한 속성 타입: 만약 동일한 이름의 속성이 같은 타입이라면, 결과 타입에서도 해당 속성은 그 타입을 가집니다.
interface HasNameString1 { name: string; }
interface HasNameString2 { name: string; }
type CombinedNameString = HasNameString1 & HasNameString2;
// 결과: { name: string; }
- 호환 가능한 속성 타입 (Union 포함): 만약 동일한 이름의 속성 타입이 서로 호환 가능하다면 (예: 한쪽이 다른 쪽의 서브타입), 더 구체적인(좁은) 타입이 됩니다. Union 타입의 경우, 두 타입의 교집합이 됩니다.
interface HasValueStringOrNumber { value: string | number; }
interface HasValueNumberOrBoolean { value: number | boolean; }
// value 속성의 타입은 (string | number) & (number | boolean)
type CombinedValue = HasValueStringOrNumber & HasValueNumberOrBoolean;
// 결과: { value: number; } (두 Union 타입의 공통 부분인 number만 남음)
const example: CombinedValue = { value: 123 }; // value는 반드시 number여야 함
// const exampleError: CombinedValue = { value: "hello" }; // 에러! string은 number가 아님
- 호환 불가능한 속성 타입 (Primitive): 만약 동일한 이름의 속성이 서로 호환 불가능한 원시 타입(primitive type)이라면, 결과 타입에서 해당 속성의 타입은 never가 됩니다. never 타입은 값이 절대 존재할 수 없음을 의미하므로, 이러한 객체를 생성하는 것은 불가능합니다.
interface HasValueNumber { value: number; }
interface HasValueString { value: string; }
// value 속성의 타입은 number & string
type ConflictValuePrimitive = HasValueNumber & HasValueString;
// 결과: { value: never; }
// const obj: ConflictValuePrimitive = { value: 123 }; // 에러! number는 never가 아님
// const obj: ConflictValuePrimitive = { value: "hello" }; // 에러! string은 never가 아님
// ConflictValuePrimitive 타입의 객체를 만들 수 있는 방법은 없습니다.
- 호환 불가능한 속성 타입 (Non-primitive): 동일한 이름의 속성이 서로 호환 불가능한 객체 타입(또는 배열, 함수 등)이라면, 결과 타입에서 해당 속성의 타입은 never가 됩니다.
interface HasDetailsObject { details: { a: number } }
interface HasDetailsArray { details: number[] }
// details 속성의 타입은 { a: number } & number[]
type ConflictDetails = HasDetailsObject & HasDetailsArray;
// 결과: { details: never; }
// ConflictDetails 타입의 객체를 만들 수 있는 방법은 없습니다.
인터페이스 vs 교차 타입
교차 타입(&)은 인터페이스의 상속(extends)과 유사한 역할이지만 몇 가지 차이점이 있다.
extends
- 주로 객체 타입을 확장할 때 사용
- 동일한 이름의 속성이 있을 경우 = 기본적으로 서브타입 관계가 성립해야 하며 그렇지 않으면 에러가 발생
- 동일한 이름의 함수 멤버는 오버로딩
&
- 객체 타입뿐만 아니라 원시 타입
- Union 타입 등 모든 타입을 결합할 수 있다.
- 동일한 이름의 속성 충돌 시 위에서 설명한 규칙(never 또는 Union의 교집합)에 따라 처리
- 기존 타입을 수정하지 않고 조합할 때 유연
대부분의 경우 객체 타입을 결합할 때 extends나 & 모두 사용할 수 있지만, 복잡한 타입 조합이나 유니온 타입과의 결합 시에는 &가 더 강력하고 유연
// extends 사용
interface A { p1: string; }
interface B { p2: number; }
interface C extends A, B {} // C는 p1, p2를 모두 가짐
// 교차 타입 사용
type D = A & B; // D는 p1, p2를 모두 가짐
const objC: C = { p1: "hi", p2: 123 };
const objD: D = { p1: "hi", p2: 123 };
교차 타입 vs 유니온 타입
정반대의 개념
| 타입 | 기호 | 의미 | 결과 타입의 속성 | 충돌 처리 | 예시 |
| 교차 타입 | & | A 이고 B | A의 모든 속성 + B의 모든 속성 | 호환 가능 시 조합, 불가능 시 never | TypeA & TypeB |
| 유니온 타입 | | | A 이거나 B | A 또는 B 둘 중 하나의 속성 집합을 가질 수 있음 | 타입 가드 필요 (typeof, in, 등) | TypeA | TypeB |
.
문제 :
문제은행 6강 교차타입 - HackMD
Product 타입:
hackmd.io
'2024~ > React' 카테고리의 다른 글
| [타입스크립트] 환경 설정 (1) | 2025.06.02 |
|---|---|
| [타입스크립트] 스포티파이 만들기 (1) | 2025.06.02 |
| [타입스크립트] 고급타입 - any, unknown, void, never~ (0) | 2025.05.31 |
| [타입스크립트] 고급 타입- enum (2) | 2025.05.31 |
| [타입스크립트] 3강- type, interface (2) | 2025.05.27 |