내가 모르고 있던 타입스크립트의 활용

2024. 02. 04

링크드인을 구경하던 도중 지인이 Matt Pocock 이라는 분을 팔로우 하고 있었습니다. Total Typescript 라는 사이트를 운영하고 있는 분이시며, 타입스크립트 관련된 글을 자주 작성 해 주시는데, 유용하면서 도움이 되었던 글들을 발췌해 보았습니다.

1. Optional Methods

JSX를 사용할 때 이벤트 핸들러를 받는 경우 빈번합니다. 저는 이벤트 핸들러를 받을 때 마다 이벤트의 시그니처를 직접 입력었습니다.

interface ClickMethods {
    onClick?: (...args): void;
}

그런데 아래와 같이 축약된 버전으로 사용할 수 있습니다.

interface ClickMethods {
  onClick?(...args: string[]): void;
}
const Count = ({ onClick }: ClickMethods) => {
  const [count ,setCount] = useState<number>(0)
  const handleOnClick = () => {
    setCount(prev => {
        const next = prev + 1
        onClick?.('user', 'name')
        return next
    })
  }
  return <div onClick={handleOnClick}>{count}</div>;
};

2. Generic의 활용

JSX에서 하나의 prop에 다른 prop이 의존하게 된다면 제네릭을 활용해서 타입을 추론 할 수 있게 합니다.

const Table = <T extends Record<string, unknown>>({
  rows,
  renderRow,
}: {
  rows: T[];
  renderRow: React.FC<T>;
}) => {
  return (
    <table>
      <tbody>{rows.map(renderRow)}</tbody>
    </table>
  );
};

3. as const object로 라우트 타입 만들기

const routes = {
  user: ['get-user', 'get-all-users'],
  comment: ['get-comment', 'get-all-comments']
} as const

type Routes = typeof routes

type AuthRoutes = {
  [K in keyof Routes]: `/${K}/${Routes[K][number]}`
}[keyof Routes]

type UserType = 'admin' | 'guest' | 'worker'

type Example = Record<AuthRoutes, UserType[]>

4. infer의 다양한 활용

tailwind 같은 특정 클래스를 강제하고 싶을 때 쓰기 좋은 타입입니다.

type InferValueFromColor<Color extends string> = Color extends `${infer N}-${infer C}-${infer T}` ? {
  namespace: N;
  color: C;
  tone: T
} : never
type Example = InferValueFromColor<'text-green-700'> // { namespace: 'text', color: 'green', tone: '700'}

parseInt로 string을 number type으로 변경할 수도 있습니다

type ParseInt<T extends string> = T extends `${infer Int extends number}` ? Int : never

이렇게 하게 된다면 위에서 정의한

type InferValueFromColor<Color extends string> = Color extends `${infer N}-${infer C}-${infer T}` ? {
  namespace: N;
  color: C;
  tone: ParseInt<T>
} : never
type Example = InferValueFromColor<'text-green-700'> // { namespace: 'text', color: 'green', tone: 700}

으로 타입을 사용할 수 있게 됩니다.


5. indexed array

const columns = [
  {
    field: 'notes',
    renderCells: () => 'asd'
  },
  {
    field: 'id',
    renderCells: () => 123
  },
] as const

type Column = (typeof columns)[number]

type ColumnMap = {
  [K in Column as K['field']]: K['renderCells'] 
}
/* 
    ColumnMap = {
        notes: () => string;
        id: () => number;
    }
*/

출처

MAPOCOCK 링크드인


© 2024 Doe의 devlog, Built with Vapor blog Theme Gatsby