Gwangju-Web-Study / WoowahanTS_Study

✏️우아한 타입스크립트 with 리액트 스터디
6 stars 2 forks source link

8.2.2. JSDocs로 타입을 지정하는 예시를 작성해주세요. #35

Closed fe-Jay closed 1 week ago

fe-Jay commented 1 week ago

📝 p 269

❓ 컴포넌트 속성 타입을 명시하기 위해 JSDocs를 사용할 수 있습니다. 원활한 협업을 위해 어떤식으로 JSDocs에 타입을 명시해볼 수 있을지, 예시를 작성해주세요.

gwangminjun commented 1 week ago
/**
 *
 * @param {Object} props - 컴포넌트
 * @param {string} props.label - 라벨
 * @param {function} props.onClick - 온 클릭 이벤트
 * @param {boolean} [props.primary] - 필수 값
 * @param {string} [props.className] - html 클래스 네임
 */
const Button: React.FC<{
  label: string;
  onClick: () => void;
  primary?: boolean;
  className?: string;
}> = ({ label, onClick, primary = false, className = '' }) => {
  return (
    <button
      className={`btn ${primary ? 'btn-primary' : 'btn-secondary'} ${className}`}
      onClick={onClick}
    >
      {label}
    </button>
  );
};

JSDocs 주석을 사용하여 props 타입을 문서화

TypeScript에서 React.FC 제네릭 타입을 사용하여 props 타입을 정의합니다.

props 타입은 JSDocs 주석에 명시된 내용과 일치

옵셔널 prop인 primary와 className은 ?로 표시

TypeScript 컴파일러가 props 타입을 자동으로 검사할 수 있습니다.

JSDocs 주석을 기반으로 자동으로 타입 정의 파일(.d.ts)을 생성할 수 있습니다.

fe-Jay commented 1 week ago

JSDocs 사용 예시

  interface ButtonProps {
    label: string;
    onClick: () => void;
    disabled?: boolean;
    variant?: 'primary' | 'secondary' | 'danger';
    size?: 'small' | 'medium' | 'large';
  }

  /**
   * 기본 버튼 컴포넌트
   * 
   * @component
   * @example
   * ```tsx
   * <Button 
   *   label="제출하기"
   *   onClick={() => console.log('clicked')}
   *   variant="primary"
   *   size="medium"
   * />
   * ```
   * 
   * @param {Object} props - 버튼 컴포넌트 속성
   * @param {string} props.label - 버튼에 표시될 텍스트
   * @param {Function} props.onClick - 클릭 이벤트 핸들러
   * @param {boolean} [props.disabled] - 버튼 비활성화 여부
   * @param {('primary'|'secondary'|'danger')} [props.variant='primary'] - 버튼 스타일 변형
   * @param {('small'|'medium'|'large')} [props.size='medium'] - 버튼 크기
   * 
   * @returns {JSX.Element} 버튼 컴포넌트
   */

  const Button: React.FC<ButtonProps> = ({ 
    label, 
    onClick, 
    disabled = false, 
    variant = 'primary',
    size = 'medium' 
  }) => {
    return (
      <button
        onClick={onClick}
        disabled={disabled}
        className={`btn btn-${variant} btn-${size}`}
      >
        {label}
      </button>
    );
  };

기업별 JSDocs 활용 사례

  1. Google Material-UI 스타일

    /**
    * Modal component that follows Material Design guidelines.
    * 
    * @see https://material.io/components/dialogs - 공식 문서 링크 제공
    * @fires {Event} onOpen - 이벤트 발생 명시
    * @fires {Event} onClose
    * @example
    * ```jsx
    * <Modal
    *   open={isOpen}
    *   onClose={handleClose}
    *   aria-labelledby="modal-title"
    * >
    *   <ModalContent>
    *     <Typography id="modal-title">Modal Title</Typography>
    *   </ModalContent>
    * </Modal>
    * ```
    */
    
    interface ModalProps {
    open: boolean;
    onClose: () => void;
    'aria-labelledby': string; // 접근성 고려
    }
    
    //
    const Modal: React.FC<ModalProps> = ({ open, onClose, children }) => {};
  2. Airbnb 스타일:

    /**
    * A composable rating component.
    * 
    * @accessibility - 접근성 관련 정보
    * Uses role="img" with aria-label for screen readers.
    * Keyboard navigation supported for interactive ratings.
    * 
    * @performance - 성능 관련 정보
    * Component is memoized to prevent unnecessary re-renders.
    * SVG icons are loaded using dynamic imports.
    */
    interface RatingProps {
    value: number;
    onChange?: (value: number) => void;
    maxRating?: number;
    }
    
    const Rating = React.memo(({ value, onChange, maxRating = 5 }: RatingProps) => {
    return (
      <div role="img" aria-label={`Rating: ${value} of ${maxRating}`} />
    );
    });

JSDocs 사용 팁

  1. ESLint 규칙 추천

    {
    "rules": {
      "jsdoc/require-jsdoc": "error",   // 모든 함수와 클래스에 JSDoc 주석 필수
      "jsdoc/require-param": "error",   // 모든 매개변수에 대한 @param 설명 필수
      "jsdoc/require-returns": "error", // 반환값에 대한 @returns 설명 필수
      "jsdoc/require-example": "error"  // 사용 예시 @example 필수
    }
    }
  2. 템플릿 스니펫

    {
    "React Component JSDoc": {
      "prefix": "jsdoc-react",
      "body": [
        "/**",
        " * ${1:컴포넌트 설명}",
        " * ",
        " * @component",
        " * @example",
        " * ```tsx",
        " * <${2:ComponentName} />",
        " * ```",
        " * ",
        " * @param {Object} props - 컴포넌트 props",
        " * @returns {JSX.Element}",
        " */"
      ]
    }
    }
hyeonseong2023 commented 1 week ago

JSDoc 장점

JSDoc 생성 및 구성

// 설치
npm install -g jsdoc
jsdoc -c jsdoc.json
// jsdoc.json
{
    "source": {
      "include": ["src"], 
      "includePattern": ".+\\.jsx?$" 
    },
    "plugins": ["plugins/markdown"], 
    "opts": {
      "recurse": true,
      "destination": "docs"
    },
    "templates": {
      "cleverLinks": false,
      "monospaceLinks": false
    }
  }

예시

import React from 'react';
import "./Button.css"

/**
* 버튼 컴포넌트
*
* @component
* @param {Object} props - text와 onClick을 props로 받습니다
* @param {string} props.text - 버튼에 표시될 텍스트
* @param {function} props.onClick - 클릭 이벤트 핸들러
* @returns {JSX.Element} 렌더링된 버튼 컴포넌트
*
* @example
* // "Click Me" 텍스트를 가진 버튼 렌더링
* <Button text="Click Me" onClick={() => console.log('Button clicked!')} />
*/
function Button({ text, onClick }) {
 return (
   <button className='myButton' onClick={onClick}>
     {text}
   </button>
 );
}

export default Button;