[React] 컴포넌트에서 제네릭 사용하기

찐새·2023년 10월 24일
0

typescript

목록 보기
8/8
post-thumbnail
post-custom-banner

타입 매개변수 제네릭 전달

타입을 구체적으로 명시하지 않고 TS의 추론에 맞긴다면, 타입 매개변수를 이용해 손쉽게 추론 가능하다.

const MyComponent = <T extends unknown>({ a, b, c }: MyComponentProps<T>) => {
  return (
    <div>
      <h1>{a}</h1>
      <h2>{b}</h2>
      <ul>
       {Array.isArray(c) ? (
          c.map((item, idx) => (
            <li key={JSON.stringify(item) + `${idx}`}>
              {JSON.stringify(item)}
            </li>
          ))
        ) : (
          <strong>{JSON.stringify(c)}</strong>
        )}
      </ul>
    </div>
  );
};

interface MyComponentProps<T> {
  a: string;
  b: number;
  c: T;
}

export default MyComponent;

ab의 타입은 고정이지만, c는 어떤 타입이 들어와도 받을 수 있다.

Mapped Type

type Mappped<T> = {
  [P in keyof T]: T[P];
};

interface MyComponentProps<T> {
  a: string;
  b: number;
  c: Mappped<T>;
}

{ [P in keyof T]: T[P] }는 Mapped Type이라고 불리는 형태이며, 이렇게 작성 시 위의 T를 그냥 사용한 것과 똑같은 결과를 나타낸다. c가 primitive 타입이라면 그 타입의 모든 속성을 props로 가지게 되고, object 타입이라면 내부 속성만 값으로 가지게 된다.

각각의 타입에 따라 위 이미지와 같은 속성을 얻게 된다.

객체만 전달

primitive나 배열이 아닌 객체 형태의 속성만 전달할 필요가 있을 수도 있다. TS의 유틸리티 타입 중 Record를 사용해 객체 타입만 받도록 지정하면 된다.

const MyComponent = <T extends Record<string, unknown>>(
        { a, b, c }: MyComponentProps<T>
  ) => {
  return (
    <div>
      {/* ... */}
    </div>
  );
};

interface MyComponentProps<T> {
  a: string;
  b: number;
  c: T;
}

Record<keyType, valueType>는 속성 key의 타입을 첫 번째 제네릭으로 받고, value의 타입을 두 번째 제네릭으로 받는다. 이렇게 T를 확장시키면 객체 이외의 c값은 오류를 발생한다.

function App() {
  const temp = {
    a: "A",
    child: [
      {
        b: "B",
        c: "C"
      }
    ]
  };
  return (
    <div className="App">
  {/* Type 'string' is not assignable to type 'Record<string, unknown>'. */}
      <MyComponent a={"a"} b={1} c={"A"} />
  {/* Type 'string[]' is not assignable to type 'Record<string, unknown>'. */} 
      <MyComponent a={"b"} b={2} c={["A", "B", "C"]} />
  {/* Type '(string | number | true)[]' is not assignable to type 'Record<string, unknown>'. */}
      <MyComponent a={"b"} b={2} c={["A", 1, true]} />
  {/* No Error */}      
      <MyComponent a={"b"} b={2} c={temp} />
    </div>
  );
}
profile
프론트엔드 개발자가 되고 싶다
post-custom-banner

0개의 댓글