인프런 커뮤니티 질문&답변

dubu777님의 프로필 이미지
dubu777

작성한 질문수

실무에 바로 적용하는 스토리북과 UI 테스트

Generic Type과 Event Bubbling을 활용한 TagList 컴포넌트

제네릭 타입을 사용하는 이유

작성

·

151

·

수정됨

1

안녕하세요 강사님 좋은 강의 잘 듣고 있습니다!
제네릭에 대한 이해를 위해서 따로 문서도 찾아봤는데 궁금증이 해결되지 않아서 질문드립니다.

제네릭 타입을 사용해서 tagList로 넘어온 아이템이 onTagClick으로 전달된다는것을 보증 해준다고 하셨는데, 제네릭의 어떤 기능으로 이것을 보증해주는지 궁금합니다.
그리고 아래처럼 작성한것과 어떤 차이가 있는지 궁금합니다.

import { useState } from "react";
import TagButton from "./TagButton";

interface ITagListProps {
  tagList: string[];
  onTagClick: (tag: string) => void;
}

export default function TagList({
  tagList,
  onTagClick,
}: ITagListProps) {
  const [selectedTag, setSelectedTag] = useState<string>(tagList[0]);
  return (
    <div className="flex gap-x-4" onClick={(event) => {
      const eventTarget = event.target as HTMLButtonElement;
      const tag = eventTarget.textContent as string
      onTagClick(tag)
    } }>
      {tagList.map((tag) => (
        <TagButton
          key={tag}
          isChecked={tag === selectedTag}
          onClick={() => setSelectedTag(tag)}
        >
          {tag}
        </TagButton>
      ))}
    </div>
  );
}

답변 2

1

dubu777님의 프로필 이미지
dubu777
질문자

와.. 이해가 됐어요 감사합니다!!
주말인데 시간내서 답해주셔서 감사합니다!
남은 주말 잘 보내세요~

1

강병진님의 프로필 이미지
강병진
지식공유자

좋은 질문 감사합니다! 제가 말로 설명 드리는 것 보다 예시를 보여드리는게 좋을 것 같아서 한 번 가져와봤어요!

generic을 사용하지 않고 타입을 string 으로 지정하면, setSelectedTag() 를 호출할 때 tag로 넘겨받지 않은값도 selectedTag 가 될 수 있습니다.

 

작성해주신 코드를 조금만 변경해보자면

import { useState } from "react";
import TagButton from "./TagButton";

interface ITagListProps {
  tagList: string[];
  onTagClick: (tag: string) => void;
}

export default function TagList({
  tagList,
  onTagClick,
}: ITagListProps) {
  const [selectedTag, setSelectedTag] = useState<string>(tagList[0]);
  return (
    <div className="flex gap-x-4" onClick={(event) => {
      const eventTarget = event.target as HTMLButtonElement;
      const tag = eventTarget.textContent as string
      onTagClick(tag)
    } }>
      {tagList.map((tag) => (
        <TagButton
          key={tag}
          isChecked={tag === selectedTag}
          onClick={() => setSelectedTag("inflearn")} // 여기서 에러 발생하지 않음
        >
          {tag}
        </TagButton>
      ))}
    </div>
  );
}

tagList 에 어떤 값이 들어오던 상관없이 selectedTag 를 자유롭게(?) 변경할 수 있게됩니다. 그래서 TypeScript를 활용하는 장점이 살짝 떨어지게 됩니다. 반면 generic을 사용하는 현재 코드를 활용하면

 

image

위 스크린샷에서 보시는 것처럼 조금 더 안정적으로 타입을 관리할 수 있습니다.

selectedTag 에서 기대하는 타입이 T 인데 setSelectedTag 호출하는 부분해서 파라미터로 리터럴 타입인 "inflearn"을 넘기게 되어 문제가 생기는건가요?

["tag1", "tag2", "tag3"]의 "tag1" 과 같은 값을 원하는게 아니라 순수하게 타입이 T인 것만 기대하는건지 궁금합니다.

강병진님의 프로필 이미지
강병진
지식공유자

네네 맞습니다 제네릭으로 선언했기 때문에 tagList 에 있는 항목들만 사용해야하는데, 다른 값이 넘어와서 에러가 난다고 보시면됩니다~

dubu777님의 프로필 이미지
dubu777

작성한 질문수

질문하기