Vue.js 를 배워보자
TypeScript에서 두 객체의 공통 요소와 내포된 객체 복사하기
_Blue_Sky_
2025. 6. 13. 22:08
728x90
TypeScript에서 두 객체의 공통 요소만 복사하는 작업은 자주 필요한 기능입니다. 특히, 객체 안에 또 다른 객체가 내포되어 있을 때, 이를 올바르게 처리하려면 얕은 복사와 깊은 복사를 고려해야 합니다. 이번 포스트에서는 두 객체의 공통 키에 해당하는 요소를 복사하되, 내포된 객체도 복사하는 방법을 예제와 함께 설명하겠습니다.
1. 문제 정의
우리가 해결하고자 하는 문제는 다음과 같습니다:
-
두 객체(source와 target)가 있을 때, 공통 키에 해당하는 값만 복사.
-
값이 객체인 경우, 해당 객체도 깊게 복사하여 원본 객체와 독립적인 복사본 생성.
-
TypeScript의 타입 안정성을 유지하면서 동적으로 처리.
728x90
예를 들어, 다음과 같은 두 객체가 있다고 가정해 봅시다:
const source = {
name: "John",
age: 30,
address: { city: "Seoul", country: "Korea" },
hobby: "reading"
};
const target = {
name: "",
age: 0,
address: { city: "", country: "", zip: "" },
job: ""
};
여기서 name, age, address는 공통 키입니다. 특히 address는 내포된 객체이므로, 이 객체의 공통 속성(city, country)만 복사해야 합니다.
2. 해결 방법
이를 위해 우리는 재귀적으로 객체를 탐색하며 공통 키를 찾아 값을 복사하는 함수를 작성할 것입니다. 얕은 복사로는 내포된 객체를 제대로 처리할 수 없으므로, 깊은 복사를 구현합니다.
2.1. 타입 정의
먼저, 동적으로 키를 처리할 수 있도록 인터페이스를 정의합니다:
interface GenericObject {
[key: string]: any;
}
이 인터페이스는 키가 문자열이고 값이 어떤 타입이든 허용하는 객체를 나타냅니다. 더 구체적인 타입이 필요하다면, 각 객체의 구조에 맞는 인터페이스를 정의할 수 있습니다.
2.2. 공통 요소 복사 함수
다음은 공통 키를 찾아 값을 복사하는 함수입니다. 내포된 객체를 처리하기 위해 재귀를 사용합니다:
function copyMatchingProperties(source: GenericObject, target: GenericObject): GenericObject {
const result: GenericObject = {};
// source와 target의 공통 키 찾기
const commonKeys = Object.keys(source).filter(key => key in target);
for (const key of commonKeys) {
const sourceValue = source[key];
const targetValue = target[key];
// 값이 객체이고 null이 아닌 경우, 재귀적으로 복사
if (
sourceValue !== null &&
targetValue !== null &&
typeof sourceValue === "object" &&
typeof targetValue === "object"
) {
result[key] = copyMatchingProperties(sourceValue, targetValue);
} else {
// 객체가 아닌 경우, source의 값을 복사
result[key] = sourceValue;
}
}
return result;
}
2.3. 함수 동작 원리
-
공통 키 필터링: Object.keys(source).filter(key => key in target)를 통해 두 객체에 모두 존재하는 키를 찾습니다.
-
값 처리:
-
값이 객체(object 타입이고 null이 아님)인 경우, 재귀적으로 copyMatchingProperties를 호출하여 내포된 객체의 공통 속성을 복사.
-
객체가 아닌 경우(예: 문자열, 숫자 등), source의 값을 그대로 복사.
-
-
결과 반환: 공통 키와 그 값(또는 재귀적으로 복사된 객체)만 포함된 새로운 객체를 반환.
728x90
3. 예제 사용
이제 위 함수를 실제 데이터에 적용해 보겠습니다:
const source = {
name: "John",
age: 30,
address: { city: "Seoul", country: "Korea", zip: "12345" },
hobby: "reading"
};
const target = {
name: "",
age: 0,
address: { city: "", country: "", zip: "" },
job: ""
};
const result = copyMatchingProperties(source, target);
console.log(result);
// 출력:
// {
// name: "John",
// age: 30,
// address: { city: "Seoul", country: "Korea" }
// }
결과 분석
-
공통 키: name, age, address.
-
address 객체의 공통 키: city, country.
-
source의 zip은 target의 address에 없으므로 복사되지 않음.
-
target의 job은 source에 없으므로 결과에 포함되지 않음.
4. 더 구체적인 타입 사용
위 예제는 GenericObject를 사용해 동적으로 처리했지만, 타입 안정성을 강화하려면 구체적인 인터페이스를 정의할 수 있습니다:
typescript
interface Address {
city: string;
country: string;
zip?: string;
}
interface Source {
name: string;
age: number;
address: Address;
hobby?: string;
}
interface Target {
name: string;
age: number;
address: Address;
job?: string;
}
function copyMatchingPropertiesTyped(source: Source, target: Target): Partial<Target> {
const result: Partial<Target> = {};
const commonKeys = Object.keys(source).filter(key => key in target) as (keyof Target)[];
for (const key of commonKeys) {
const sourceValue = source[key];
const targetValue = target[key];
if (
key === "address" &&
sourceValue !== null &&
targetValue !== null &&
typeof sourceValue === "object" &&
typeof targetValue === "object"
) {
result[key] = copyMatchingProperties(sourceValue, targetValue) as Address;
} else {
result[key] = sourceValue;
}
}
return result;
}
이 버전은 Source와 Target의 구조를 명시적으로 정의하여 타입 오류를 줄이고, Partial<Target>을 반환 타입으로 사용하여 선택적 속성을 지원합니다.
5. 주의사항
-
깊은 복사: 이 함수는 공통 키에 대해 깊은 복사를 수행합니다. 하지만 배열이나 Date 객체 등 특수 객체는 별도로 처리해야 할 수 있습니다.
-
성능: 재귀 호출은 객체가 깊게 중첩된 경우 성능에 영향을 줄 수 있으므로, 큰 객체를 다룰 때는 최적화를 고려하세요.
-
타입 안정성: 동적 키를 사용할 때는 any 대신 가능한 한 구체적인 타입을 사용하는 것이 좋습니다.
6. 결론
TypeScript에서 두 객체의 공통 요소를 복사하는 작업은 간단해 보이지만, 내포된 객체를 처리하려면 재귀적 접근이 필요합니다. 이 포스트에서 제공한 함수는 공통 키를 찾아 값을 복사하며, 내포된 객체도 올바르게 처리합니다. 타입 안정성을 강화하려면 구체적인 인터페이스를 정의하는 것이 좋습니다. 이 코드를 기반으로 여러분의 프로젝트에 맞게 커스터마이징해 보세요!
728x90