Для фронтенд-разработчика создание собственного компонента — обычное дело, либо с нуля, либо путем наслоения на основе библиотеки компонентов. Но проблема в том, что иногда мы не знаем, каковы именно реквизиты этого компонента или каков выбор реальных реквизитов.

После работы в компании Software House ±2 года. Я понимаю, что компонент JSDoc для React является обязательным, поскольку мы часто меняем разработчика для одного проекта или отдаем кодовую базу клиенту, чтобы он не сказал: «ЧЕГО ЭТО КОД?».

В любом случае, почему бы тогда не использовать TypeScript? Представьте себе, что вы работаете в старой компании, которая строго хочет сохранить устаревший код, ИЛИ работаете с клиентом, который не хочет изучать новый язык программирования. Конечно, вы застрянете с JavaScript, пока будете работать с ними.

Итак, без лишних слов, приступим.

Установка

Для технического стека я использую React с Vite в качестве инструментов сборки, Antd и Axios.

Прежде всего, просто создайте React App с помощью Vite (также работает с CRA).

npm create vite@latest
// or with yarn
yarn create vite

// after that, setup the react app with vite, change the dir to the project
// and then install the packages

npm install
// or with yarn
yarn install

// after that, install antd and axios

npm install antd axios
// or with yarn
yarn add antd axios

После настройки и установки зависимостей я настраиваю папку, так как это всего лишь туториал, мне не нужен сложный, мне нужна только папка Components и удаляю ненужные файлы, так что станет как этот.

Наконец, добавьте свой пользовательский компонент в папку Components. Сегодня мы возьмем в качестве примера кнопку. Я также добавляю префикс «dj-», чтобы избежать путаницы между нашим заказным компонентом и компонентом из библиотеки (это действительно необязательно, либо вы меняете на то, что вам нравится, либо просто оставить его без префикса). Я также добавляю style.css в папку компонента, чтобы использовать его позже.

Шаблон для компонента

Эта статья написана, когда Ant Design еще находился в V5.2.0. В этой версии компонент кнопки имеет только 2 цвета: синий по умолчанию и красный как опасность. (Кнопка — Дизайн Муравей). Иногда нашему клиенту нужен другой вариант, например, зеленый для успеха или желтый для предупреждения. Итак, позвольте мне дать шаблон ниже.

// src/components/dj-button/index.jsx
import { Button } from "antd";

import "./style.css";

// Variant will determine the color of button, 
// we will add green and yellow also 
// red, blue is default value from antd.

// I also add type even though there is exist in 
// object for default value purpose.
export const DJButton = ({
  children,
  type = "primary",
  variant = "blue",
  ...props
}) => {
  return (
    <Button
      className={`${props.className || ""} dj-button dj-button--${variant}`}
      type={type}
      {...(variant === "red" && { danger: true })}
      {...props} // Pass the default props from Antd Button Component
    >
      {children}
    </Button>
  );
};

Конечно, внутри style.css также используется для перекрашивания.

/* src/components/dj-button/style.css */

/*
 * Since the blue colour is Antd default colour and
 * red colour is already handled with "danger" props
 * we don't need those here.
 **/

.dj-button--green {
  background-color: #52c41a;
}
.dj-button--green:hover {
  background-color: #95de64 !important;
}

.dj-button--yellow {
  background-color: #faad14;
}
.dj-button--yellow:hover {
  background-color: #ffd666 !important;
}

Давайте проверим это, разместив на странице. В моем случае я помещу его в App.jsx.

// src/App.jsx

...
function App() {
  return (
    <div className="App">
      <DJButton>Custom</DJButton>
    </div>
  );
}

Должен отображаться на странице, но что, если мы хотим добавить свойства, которые существуют в документации кнопки Antd? Что делать, если мы хотим изменить вариант цвета? Есть ли какие-либо предложения внутри intellisense?

Только 4? Кроме того, тип и вариант не имеют выбора. Это плохо для разработчиков, поскольку они не знают, что они должны заполнить внутри этих двух. Здесь на помощь приходит JSDoc.

JSDoc: передача реквизитов из других зависимостей

JSDoc обширен, поэтому я не буду описывать его все. В этой статье я расскажу, как использовать @typedef, @property, @param и @returns. Другие теги см. в разделе Использовать JSDoc: индекс.

Прежде всего, мы хотим убедиться, что компонент из библиотеки имеет свойства, чтобы проверить это, обычно просто наведите курсор на код компонента. Но если вам такой реквизит не имеет никакого смысла…

Мы должны искать их либо ctrl+щелкнуть левой кнопкой мыши, чтобы увидеть основной файл, либо просто использовать intellisense внутри импорта, как я…

После этого добавьте комментарий над кодом вашего пользовательского компонента.

// src/components/dj-button/index.jsx
import { Button, ButtonProps } from "antd";

import "./style.css";

/**
 * @typedef {ButtonProps} AntdButtonProps
 *
 * @param {AntdButtonProps} props
 */
export const DJButton = ({ 
  children, 
  type = "primary", 
  variant = "blue", 
  ...props}) => {...}

Всегда используйте комментарий /** */, иначе он не будет работать. Передайте реквизиты внутри тега @typedef, а затем назовите его, мой — AntdButtonProps, так как он поставляется с Ant Design. После этого перейдите внутрь тега @param.

Посмотрим, работает это или нет.

Хорошо, теперь это работает.

JSDoc: Реквизит, сделанный нами (разработчик)

Хорошо, а как насчет сделанного нами реквизита? Допустим, свойство variant. Это должен быть выбор, например, синий, зеленый, желтый и красный, верно? Почему сейчас написано «Нет предложений»?

Потому что мы не включаем их в JSDoc, который мы написали ранее. Включить его очень просто, мы используем @typedef, как и раньше, и комбинируем его с ‘&’ в @param.

// src/components/dj-button/index.jsx

/**
 * @typedef {ButtonProps} AntdButtonProps
 *
 * @typedef {object} DJButtonProps
 * @property {'blue' | 'green' | 'yellow' | 'red'} [variant] 
 *
 * @param {AntdButtonProps & DJButtonProps} props
 */

и ваш intellisense будет выглядеть так…

Вуаля, это работает!

Кстати, вы заметили, что тег variant в теге @property находится внутри квадратных скобок. Пожалуйста, делайте это каждый раз, когда написанное вами свойство считается необязательным. Это сообщит intellisense как необязательный, добавив «?» после имени реквизита.

JSDoc: отделить JSDoc от кода пользовательского интерфейса

Хорошо, мы подошли к концу, иногда наши реквизиты слишком чертовы, так что файл с кодом пользовательского интерфейса содержит более 500 строк кода, что не совсем идеально.

Слишком разделен, что не так уж и сложно. Сначала создайте новый файл *.js. Поскольку это для компонента, я хотел бы собрать его вместе с файлом index.jsx. Назовите файл как угодно, но при этом иметь смысл. Я назову его i.d.js.

Затем поместите JSDoc в файл *.js. Есть некоторые изменения, которые я хотел бы представить для вас.

  1. Вы можете импортировать реквизит встроенный
  2. Вы можете добавить описание для документации реквизита

Вот код…

// Inside of file *.js for interface
/**
 * @typedef {import('antd').ButtonProps} AntdButtonProps
 *
 * @typedef {object} DJButtonProps
 * @property {'blue' | 'green' | 'yellow' | 'red'} [variant]
 * You can add the description for variant props below the property tag.
 *
 * Also you can format it like md file, so you can add table, code snippet, whatever.
 *
 * *This Italic* **This Bold** `This Code`
 * @property {import('react').ReactNode} [children]
 *
 * @typedef {AntdButtonProps & DJButtonProps} IDJButton
 */

export {};

А внутри файла index.jsx это будет выглядеть так…

// src/components/dj-button/index.jsx
import { Button } from "antd";

import "./style.css";

/**
 * @param {import('./i.d').IDJButton} props
 */
export const DJButton = ({
  children,
  type = "primary",
  variant = "blue",
  ...props
}) => ...};

ИЛИ, поскольку этот компонент возвращает React Functional Component, вы также можете написать JSDoc именно так…

/**
 * @type React.FC<import('./i.d').IDJButton>
 */

После этого давайте посмотрим на наш компонент внутри файла страницы…

Точно так же, как и раньше, за исключением того, что теперь есть описание, чтобы рассказать другому инженеру или нам в будущем, о чем именно этот реквизит.

Дай мне завернуть это

Разработчики редко игнорируют документацию, потому что помимо того, что код становится более подробным, на его написание требуется время. Но нравственно правильно записывать то, что мы написали, чтобы напомнить себе в будущем об облегчении жизни другим.

Бьюсь об заклад, у вас есть более эффективный способ написания JSDoc. Если это так, пожалуйста, обсудите это в комментарии, я хотел бы рассмотреть ваш способ в этой статье.

Спасибо за прочтение.