객체를 얕은 복사할 때, 전개 연산자(...)를 많이 사용합니다.
객체 전개 연산자 (Object Spread) 라는 단어처럼 연산자 앞에 객체만 가능할 것이라고 생각했는데요.
아니었습니다.
포스팅 제목과 같은 고민을 하게 된 계기는, 객체 전개 연산자를 특이하게 사용한 코드를 이해하려고 했기 때문인데요.
검색 기능을 제공하는 사이트에서, 필터링 기능을 구현할 때 쿼리 스트링 (URL 파라미터)을 많이 사용하는데, 특정 쿼리를 넘기고 싶지 않을 때가 있습니다.
// 쿼리스트링
const query = {
name: name,
age: age,
...(isCategory && { category: category }) // isCategory 값에 따라 category 쿼리 유무를 결정
};
// 쿼리스트링을 이용해 라우팅
router.push({
pathname: '/search'
query: query
});
위의 경우처럼 query라는 객체에 isCategory 값에 따라 category 프로퍼티와 값을 전달할 수도 있고, 제거할 수도 있습니다.
isCategory 값이 truthy이면, ...{ category: category }
의 결과값이 query 객체로 복사가 됩니다.
isCategory가 falsy이면, ...isCategory
의 결과값이 query 객체로 복사가 됩니다.
그렇다는 말은 isCategory의 값이 undefined, null, 0, '', false
될 수 있는데 이 값들 앞에 객체 전개 연산자를 사용할 수 있다는 의미입니다.
// ???
...undefined
...null
...0
...false
...''
객체 전개 연산자를 이용하면, 위의 값들은 객체에 어떻게 전달될까요?
MDN 문서를 확인해보고 해당 문서에 참조된, tc39/proposal-object-rest-spread README 문서에 다음과 같이 적혀있었습니다.
Null/Undefined Are Ignored
let emptyObject = { ...null, ...undefined }; // no runtime error
위의 내용을 살펴보면, "특정값들은" 객체 전개 연산자를 사용하더라도 무시되고, 런타임 에러를 발생하지 않는다는 것을 알게 됩니다.
자바스크립트에서 어떻게 동작하는 지 한번 확인해보도록 하겠습니다. (크롬 브라우저 개발자 도구를 이용)
크롬 브라우저에서 테스트
몇 가지 원시타입을 테스트해보았는데요.
undefined, null, number, boolean 타입의 경우, 객체 전개 연산자를 사용하면 런타임 오류는 발생하지 않지만, 무시 (ignore) 처리되는 걸 확인할 수 있습니다. 모든 경우 객체에 아무런 복사행위를 하지 않습니다.
그렇다면, 참조타입에 객체 전개 연산자를 사용하면 어떨까요?
배열, 문자열, Set, Map 들을 테스트해봤는데요.
배열과 문자열의 경우, 인덱스가 프로퍼티가 되어 객체 안에 값이 복사가 된 것을 확인했습니다.
그런데, Set과 Map은 무시되었습니다.
일단은, 배열과 문자열만 객체로 복사가 되는 것 같습니다.
타입스크립트 환경에서 타입 에러 체크 (TS Playground)
- 타입스크립트 버전 V5.3.3 기준
원시타입의 경우, 타입에러를 표시합니다. ( Spread types may only be created from object types.(2698) )
실행을 해보면, 콘솔에 빈 객체만 찍히는 데요.
런타임 에러는 발생하지 않았습니다.
참조타입을 비롯해서, 이터러블 가능한 값들을 테스트해봤습니다.
참조타입은 타입에러를 발생시키지 않는데요.
위의 크롬 개발자 도구에서 테스트한 것과 마찬가지로 런타임 결과는 동일했습니다.
'123', [1, 2, 3]의 경우 인덱스를 프로퍼티로 갖는 값을 객체로 복사
Set과 Map은 무시됨
결론
객체 전개 연산자 라는 말처럼 객체 앞에서만 사용하는 것이 가장 적절해 보입니다.
하지만, 위의 내용을 바탕으로 객체를 조건적으로 전달하는 코드를 작성할 수 있을 것 같습니다.
참고
ts39/proposal-object-spread/Spread.md
'TypeScript' 카테고리의 다른 글
[Typescript] 제네릭 타입을 문자열 리터럴 타입으로 제한하는 몇 가지 방법 (0) | 2024.01.21 |
---|---|
[Typescript] 자료구조 : 큐 (Queue) (0) | 2023.02.22 |
[Typescript] 자료구조 : 스택 (Stack) (0) | 2023.02.22 |
[Typescript] 자료구조 : 이중 연결 리스트 (doubly-LinkedList) (0) | 2023.02.19 |
[Typescript] 자료구조 : 단방향 연결 리스트 (Singly-LinkedList) (0) | 2023.02.18 |