[TS] 유틸리티 타입

유틸리티 타입을 활용하여 타입 중복 선언 제거

  • Props 타입과 styled-components 타입은 똑같은 타입으로 두 타입을 각각 선언하면 중복된 코드가 생긴다. 그리고 타입이 변경되면 두 타입을 모두 변경해줘야 하는 번거러움이 발생한다.
  • 유틸리티 타입인 Pick 을 활용하면 중복된 코드를 작성하지 않아도 되고 유지보수를 더욱 편리하게 할 수 있다. 이외에도 상속받는 컴포넌트 혹은 부모 컴포넌트에서 자식 컴포넌트로 넘겨주는 props 등에도 활용할 수 있다.
// 컴포넌트
export type Props = {
height?: string;
color?: string;
isFull?: boolean;
className?: string;
};
const Hr: FC<Props> = ({ height, color, isFull, className }) => {
return (
<HrComponent
height={height}
color={color}
isFull={isFull}
className={className}
/>
);
};
// 스타일 컴포넌트
type StyledProps = Pick<Props, 'height' | 'color' | 'isFull'>;
export const HrComponent = styled.hr<StyledProps>`
height: ${({ height }) => height || '10px'};
margin: 0;
background-color: ${({ color }) => color || 'gray'};
border: none;
${({ isFull }) =>
isFull &&
css`
margin: 0 -15px;
`}
`;

커스텀 유틸리티 타입 구현

  • 타입스크립트에는 서로 다른 2개 이상의 객체를 유니온 타입으로 받을 때 타입 검사기가 제대로 진행되지 않는 문제가 있다.
  • 이는 집합 관점에서 볼 때 유니온은 합집합이 되기 때문이다. 모든 객체의 속성이 모두 포함되어도 합집합의 범주에 들어가기 때문에 타입 에러가 발생하지 않는다.
type Card = {
card: string;
};
type Account = {
account: string;
};
function withdraw(type: Card | Account) {
// TODO
}
withdraw({ card: '신한', account: '하나' });
  • 식별할 수 있는 유니온으로 문제를 해결할 수 있지만 일일이 판별자를 넣어줘야 하는 불편함이 발생한다. 이미 구현된 상태에서 식별할 수 있는 유니온을 적용하려면 해당 함수를 사용하는 부분을 모두 수정해야 한다. 실수로 수정하지 않은 부분이 생긴다면 또 다른 문제가 발생할 수 있다.
type Card = {
type: 'card';
card: string;
};
type Account = {
type: 'account';
account: string;
};
function withdraw(type: Card | Account) {
// TODO
}
withdraw({ type: 'card', card: '신한' });
withdraw({ type: 'account', account: '하나' });
  • 하나의 속성을 제외한 나머지 값을 옵셔널 타입 + undefined 로 설정하면 원하고자 하는 속성만 받도록 구현할 수 있다.
type Card = { card: string };
type Account = { account: string };
type One<T> = { [P in keyof T]: Record<P, T[P]> }[keyof T];
const one: One<Card> = { card: '신한' };
type ExcludeOne<T> = {
[P in keyof T]: Partial<Record<Exclude<keyof T, P>, undefined>>;
}[keyof T];
// type PickOne<T> = One<T> && ExcludeOne<T>
type PickOne<T> = {
[P in keyof T]: Record<P, T[P]> &
Partial<Record<Exclude<keyof T, P>, undefined>>;
}[keyof T];
const pickOne1: PickOne<Card & Account> = { card: '신한' };
const pickOne2: PickOne<Card & Account> = { account: '하나' };
const pickOne3: PickOne<Card & Account> = { card: '신한', account: undefined };
const pickOne4: PickOne<Card & Account> = { card: undefined, account: '하나' };
type CardOrAccount = PickOne<Card & Account>;
function withdraw(type: CardOrAccount) {
// TODO
}
withdraw({ card: '신한', account: '하나' }); // 타입 에러

'TypeScript' 카테고리의 다른 글

[TS] 불변 객체 타입  (0) 2025.01.29
[TS] NonNullable로 타입 가드  (0) 2025.01.28
[TS] 조건부 타입  (0) 2025.01.26
[TS] 식별할 수 있는 유니온, Exhaustiveness Checking  (1) 2025.01.25
[TS] 타입 가드  (1) 2025.01.24