Item 20: “변수의 값은 바뀔 수 있지만, 그 타입은 보통 바뀌지 않는다.”
→ JS 패턴을 TS로 모델링하는 것이 쉬워짐
→ 여러 속성을 포함해 한꺼번에 생성하는 것이 타입 추론에 유리
(worse. 객체 생성 시 속성을 하나씩 추가하는 방식)
/** JS에서 2차원 점을 표현하는 객체 생성법 */
// TS에서 발생하는 할당문에서의 오류
const pt = {};
pt.x = 3; // ~ '{}' 형식에 'x'속성이 없습니다.
pt.y = 4; // ~ '{}' 형식에 'y'속성이 없습니다.
pt
타입 : {}
값을 기준으로 추론되므로Point
인터페이스 추가 시 오류 변경 내용 interface Point { x: number; y: number;}
const pt: Point = {}; // ~ '{}' 형식에 'Point' 형식의 x, y 속성이 없습니다.
pt.x = 3;
pt.y = 4;
sol. 객체를 한 번에 정의
const pt = {
x: 3,
y: 4,
}; // 정상
as
) 사용해 타입 체커 통과 const pt = {} as Point;
pt.x = 3;
pt.y = 4; // 정상
// 위의 경우도 선언 시 객체를 한꺼번에 만드는 것이 나음
const pt: Point = {
x: 3,
y: 4,
};
작은 객체를 조합해 큰 객체를 만드는 경우
const pt = {x: 3, y: 4};
const id = {name: 'Pythagoras'};
const namedPoint = {};
Object.assign(namedPoint, pt, id);
namedPoint.name;
// ~~~ '{}' 형식에 'name' 속성이 없습니다.
…
)를 사용하는 경우 const namedPoint = {...pt, ...id};
namedPoint.name; // 정상, 타입이 string
객체 전개 연산자 사용 시 이점
const pt0 = {};
const pt1 = {...pt0, x: 3};
const pt: Point = {...pt1, y: 4}; // 정상
: 간단한 객체 생성을 위해 우회하였으나, 객체 속성 추가 & TS의 새로운 타입 추론에 유용 타입에 안전한 방식으로 조건부 속성 추가 시 : null
or {}
로 객체 전개 사용
declare let hasMiddle: boolean;
const firstLast = {first: 'Harry', last: 'Truman'};
const president = {...firstLast, ...(hasMiddle ? {middle: 'S'} : {})};
const president: {
middle?: string;
first: string;
last: string;
}
전개 연산자 사용 → 한꺼번에 여러 속성 추가
```jsx
declare let hasDates: boolean;
const nameTitle = {name: 'Khufu', title: 'Pharaoh'};
const pharaoh = {
...nameTitle,
...(hasDates ? {start: -2589, end: -2566} : {})
};
```
```jsx
/** 유니온 타입으로 추론되는 pharaoh */
const pharaoh: {
start: number;
end: number;
name: string;
title: string;
} | {
name: string;
title: string;
}
```
- → 해당 타입에서는 start를 읽을 수 없음
```jsx
pharaoh.start
// ~~~~~~ '{ name: string; title: string; }' 형식에
// 'start' 속성이 없습니다.
```
해당 경우는 `start`와 `end`가 항상 함께 정의됨
→ 유니온을 사용하는 것이 가능한 값의 집합을 더 정확히 표현 O
유니온보다 선택적 필드가 다루기에 더 쉬울 수 있음
- 선택적 필드 방식으로의 표현법 → 헬퍼 함수 사용
```jsx
function addOptional<T extends object, U extends object>(
a: T, b: U | null
): T & Partial<U> {
return {...a, ...b};
}
const pharaoh = addOptional(
namedTitle,
hasDates ? {start: -2589, end: -2566} : null
);
pharaoh.start // 정상, 타입이 number | undefined
```
객체나 배열을 변환해 새로운 객체나 배열을 생성하고 싶은 경우
→ 루프 대신 내장된 함수형 기법 or 로대시(Lodash)와 같은 util 사용 권장
→ 한꺼번에 객체 생성하기 관점에서 더욱 옳은 방식
{…a, …b}
) 사용