개발/프론트엔드 (JS & React)

[React & Storybook] 3 - 타입스크립트로 스토리 작성하기

jungwon_ 2022. 9. 29. 00:00

현재 진행중인 사이드 프로젝트에 리액트, 타입스크립트, 스토리북을 사용하고있다.

 

이 글에서는 타입스크립트로 스토리를 작성하는 방법을 정리하고자 한다.

 

만약 스토리에 대해 익숙하지 않다면 아래 두 글을 먼저 확인하자.

 

[React & Storybook] 1 - 리액트에서 스토리북 사용하기

이 글에서는 스토리북과 스토리가 무엇인지 알아보고 리액트에서 스토리북(Storybook)을 시작하는 방법을 다뤄보자. 스토리북이란? 우선 스토리북은 무엇이고 왜 사용할까? 공식 문서에서 설명하

jwdevv.tistory.com

 

[React & Storybook] 2 - 스토리 작성 방법

이전글에서 기존 리액트 프로젝트에 스토리북을 추가하는 방법을 알아보았다. [React & Storybook] 1 - 리액트에서 스토리북 사용하기 이 글에서는 스토리북과 스토리가 무엇인지 알아보고 리액트에

jwdevv.tistory.com


우선 타입스크립트와 비교를 위해 자바스크립트 코드를 먼저 보자.

 

자바스크립트에서는 아래와 같이 스토리를 작성한다.

// Button.stories.js
import React from 'react';
import Button from './Button';

export default {
  title: 'Button',
  component: Button
}

const Template = (args) => <Button {...args} />;

export const Story1 = Template.bind({});
Story1.args = {
  primary: true,
  label: 'click'
}

 

이제 위와 같이 기본적인 스토리를 어떻게 타입스크립트로 구현하는지 알아보자.

 

우선 스토리북에는 리액트를 위한 ComponentMetaComponentStory 타입이 있다.

 

ComponentMeta와 ComponentStory타입이 무엇인지 알아보기 전에 Meta와 Story 타입에 대해 우선 정리해보자.

 

이전에는 스토리북에서 모든 프레임워크를 위해 오직 Meta와 Story 타입을 사용했는데, 이러한 방식은 아래 코드와 같이 prop을 스토리에 전달하기 위해 따로 export해야만 했다.

import type { Meta, Story } from '@storybook/react'
import { Button, ButtonProps } from './Button'

export default {
  title: 'Button',
  component: Button
} as Meta<ButtonProps>

const Template: Story<ButtonProps> = (args) => <Button {...args} />

하지만 이런식으로 prop 타입을 export하는 것은 오직 스토리북을 위한 것일뿐, 컴포넌트와는 아무런 연관이 없었다.

 

이런 불편한 점을 개선하기 위해 스토리북 6.3부터 ComponentStory와 ComponentMeta 타입을 사용하면 스토리북이 알아서 컴포넌트로부터 prop 타입을 불러오도록 바뀌었다.

 

따라서 타입스크립트 리액트 프로젝트에서 스토리북을 사용하고자 하는 경우 아래와 같이 스토리를 작성하면 된다.

import React from 'react'
import type { ComponentMeta, ComponentStory } from '@storybook/react'
import Button from './Button'

export default {
  title: 'Button',
  component: Button
} as ComponentMeta<typeof Button>

const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />

export const Primary = Template.bind({})
Primary.args = {
  primary: true
}

Reference

- What is the difference between these typescript types and which ones should I use? [Github Discussions] in storybookjs/storybook