inflearn logo
강의

Course

Instructor

Storybooks and UI tests that can be applied directly to practice

TagList Component Using Generic Types and Event Bubbling

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

313

dubu777

7 asked

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>
  );
}

react typescript tailwind-css storybook ui-testing

Answer 2

1

dubu777

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

1

jasonkang

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

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

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

0

suinkim

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

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

0

jasonkang

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

스토리북에 대해서

0

58

1

Storybook 10에서 argTypes에 action 설정 시

0

75

1

storybook setup

0

89

2

실무 적용 관련해서 질문이 있습니다!

0

67

2

storybook 프로젝트 세팅 중 궁금한 점이 있습니다.

0

137

2

스토리북 테스트에 대한 질문

0

102

2

tailwind 4.x 버전 변경된 CSS 추출(?) 커맨드

1

213

2

스토리북 테마에 대해 질문 드립니다.

0

159

2

테일윈드를 안쓰고 스타일 컴포넌트만 사용하는 환경에서는요?

0

146

2

[질문 x 공유용] tailwind v4.0 으로 강의랑 다를 때 (import 다름, tailwind.config.js 없어짐 등)

6

486

2

react-toastify 를 storybook에 출력 시키기

0

181

1

react에서 modal & portal 사용시 에는 어떻게 작성해야될까요

0

375

3

tsconfig

0

180

1

vite 초기설정

0

347

2

스토리 내 args에서 에러가 발생합니다.

0

209

2

Nextjs에서 tailwind를 사용할 때

0

282

2

제공해주시는 Figma 색상 코드가 강의와 달라 글 남깁니다!

0

144

2

Visual Test

1

127

1

NavigationBar 배경색

0

129

1

defaultValue 질문 드립니다!

0

123

1

svg를 public 말고 src>assets안에 넣는다면 import를 어떻게해야하나요?

1

269

2

index.tsx 빌드 오류

0

374

2

tailwind css 코드 스플릿팅이 가능한가요?

0

282

1

StoryBook 관련 궁금 사항입니다.

1

263

1