Vue.js 를 배워보자

TypeScript에서 두 객체의 공통 요소와 내포된 객체 복사하기

_Blue_Sky_ 2025. 6. 13. 22:08
728x90
 

TypeScript에서 두 객체의 공통 요소만 복사하는 작업은 자주 필요한 기능입니다. 특히, 객체 안에 또 다른 객체가 내포되어 있을 때, 이를 올바르게 처리하려면 얕은 복사와 깊은 복사를 고려해야 합니다. 이번 포스트에서는 두 객체의 공통 키에 해당하는 요소를 복사하되, 내포된 객체도 복사하는 방법을 예제와 함께 설명하겠습니다.

1. 문제 정의
우리가 해결하고자 하는 문제는 다음과 같습니다:
  • 두 객체(sourcetarget)가 있을 때, 공통 키에 해당하는 값만 복사.
  • 값이 객체인 경우, 해당 객체도 깊게 복사하여 원본 객체와 독립적인 복사본 생성.
  • 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. 함수 동작 원리
  1. 공통 키 필터링: Object.keys(source).filter(key => key in target)를 통해 두 객체에 모두 존재하는 키를 찾습니다.
  2. 값 처리:
    • 값이 객체(object 타입이고 null이 아님)인 경우, 재귀적으로 copyMatchingProperties를 호출하여 내포된 객체의 공통 속성을 복사.
    • 객체가 아닌 경우(예: 문자열, 숫자 등), source의 값을 그대로 복사.
  3. 결과 반환: 공통 키와 그 값(또는 재귀적으로 복사된 객체)만 포함된 새로운 객체를 반환.

 
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.
  • sourceziptargetaddress에 없으므로 복사되지 않음.
  • targetjobsource에 없으므로 결과에 포함되지 않음.

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;
}
이 버전은 SourceTarget의 구조를 명시적으로 정의하여 타입 오류를 줄이고, Partial<Target>을 반환 타입으로 사용하여 선택적 속성을 지원합니다.

5. 주의사항
  • 깊은 복사: 이 함수는 공통 키에 대해 깊은 복사를 수행합니다. 하지만 배열이나 Date 객체 등 특수 객체는 별도로 처리해야 할 수 있습니다.
  • 성능: 재귀 호출은 객체가 깊게 중첩된 경우 성능에 영향을 줄 수 있으므로, 큰 객체를 다룰 때는 최적화를 고려하세요.
  • 타입 안정성: 동적 키를 사용할 때는 any 대신 가능한 한 구체적인 타입을 사용하는 것이 좋습니다.

6. 결론
TypeScript에서 두 객체의 공통 요소를 복사하는 작업은 간단해 보이지만, 내포된 객체를 처리하려면 재귀적 접근이 필요합니다. 이 포스트에서 제공한 함수는 공통 키를 찾아 값을 복사하며, 내포된 객체도 올바르게 처리합니다. 타입 안정성을 강화하려면 구체적인 인터페이스를 정의하는 것이 좋습니다. 이 코드를 기반으로 여러분의 프로젝트에 맞게 커스터마이징해 보세요!
 
728x90