typescript의 Mapped type에 대해

Yeongjong Kim·2021년 9월 26일
0

Mapped type

mapped type은 객체에 대한 type을 지정할 때, property key 혹은 value를 조금 더 유연하게 지정하도록 도와준다. 유연하다는 의미는, 마치 Js의 computed property names 문법 처럼 사용할 수 있다는 의미이다. 이를 잘 활용하면 typescript에서 제공하는 type utils를 넘어서 나만의 utils를 만들고 싶을 때, 유용하게 사용할 수 있다.

js compomputed property names 예시

let param = 'size'
let config = {
  [param]: 12,
  ['mobile' + param.charAt(0).toUpperCase() + param.slice(1)]: 4
}

Mappted type 응용

  1. 객체의 key는 모르지만 type은 알고있는 경우, 다음과 같이 작성할 수 있다. 이 문법은 interface에도 적용가능하다.
type OnlyBools = {
  [key: string]: boolean;
};

interface OnlyBools = {
  [key: string]: boolean;
};
  1. PropertyKes(보통 keyof 로 추출한 key들)을 통해 type의 key를 지정하고 싶은 경우.
// Generic 문법으로 Type(type|interface)을 받아 입력받은 Type과 동일한 key에 원하는 type으로 변경할 수 있다.
type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};
// -readonly를 통해 readonly를 제거할 수 있도 있다.
type deleteReadonly<Type> = {
  -readonly [Property in keyof Type]: Type[Property];
};

// -?를 통해 optional 타입을 제거한다.
type deleteOptional<Type> = {
  [Property in keyof Type]-?: Type[Property];
};
  1. key Remapping vis as
    본인이 Mappted type을 알아보게된 계기다. 기존에 Image 컴포넌트에서 사용할 ImageProp이라는 type을 만들었다. 이 type이 상위 컴포넌트에서 사용되었을 때, ImageProp내의 type과 상위 컴포넌트 혹은, 다른 하위 컴포넌트에서 지정한 type의 이름이 겹쳐 혼란스러울 수 있다. 이 때 다음과 같이 typePrefixer를 만들어 사용해보자.
type TypePrefixer<Type, S extends string> = {
  [Property in keyof Type as `${S}${Capitalize<string & Property>}`]: Type[Property];
};

interface ImageProps
  id: string;
  src: string;
  alt: string;
  $width?: string | number;
}

export type AvatarProps = TypePrefixer<Omit<ImageProps, '$width'>, 'image'> & {
  src: string;
  userName: string;
  size?: 'small' | 'medium' | 'large';
};

// 결과
type AvatarProps = {
  imageId: string;
  imageSrc: string;
  imageAlt: string;
  src: string;
  userName: string;
  size?: 'small' | 'medium' | 'large';
}

마치며

타입마다 id를 imageId처럼 상세하게 미리 지정할 수도 있지만, Image 컴포넌트를 사용할 때는 굳이 imageId로 key로 설정하지 않더라도 id가 imageId 임을 알 수 있기 때문에 3번 예제처럼 필요한 경우에만 typePrefixer로 key이름을 바꿔주는 방법도 좋은 대안이라고 생각한다.

참고

  1. compomputed property names: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names

  2. Mapped Types: https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

profile
Front 💔 End

0개의 댓글