6.5 KiB
TypeScript и React
Types и components
- Сохраняй strict TS profile и
import type. Для недоверенного значения используйunknownс narrowing;anyне заменяет DTO/validation. Локальное исключение на нетипизированной boundary должно быть узким и объяснённым. - Строковые
enumиспользуются для machine codes и protocol values.namespaceне используется; tooling сохраняетerasableSyntaxOnly. Для состояния с разными payload выбирай discriminated union; не добавляй необязательные поля, допускающие невозможные комбинации. - Named components — const-valued
FC<Props>; named props находятся рядом или в types-файле. Принимайprops, destructure в body, без inline props typing. Только children —FC<PropsWithChildren>; дополнительные props — named type на основеPropsWithChildren<{ … }>; без props —FC. - Обычные exports — нижний named block; barrel делает прямой re-export. CSF сохраняет default meta и прямые story exports; configuration exceptions заданы в ESLint. Не распространяй их на application code.
Читаемость: ESLint и review
ESLint проверяет ограничение 80 символов (tab = 2), пустые строки между
JSX siblings и вокруг многострочных declarations/control-flow/return, вынос
функций и условных выражений из JSX props, отдельные Zod schema files,
отсутствие SVG в приложении, optional trailing parameters и многострочные
сложные union types. Generated artifacts не форматируй вручную.
URL, строковые/template/regex literals и комментарии исключены из max-len;
это исключение для содержимого, а не повод собирать длинные expressions.
CSS и Markdown также держи в 80 колонках там, где это не ломает данные/ссылки.
Review проверяет то, чего синтаксис не доказывает:
- Пустая строка отделяет смысловые шаги: inputs, вычисления, действие, результат.
- Имена derived values описывают значение, например
projectedAmount. - Тернарник остаётся коротким выбором двух значений. Mapping, несколько веток
и многострочное преобразование — отдельная функция с guard и
if/else. - Union из object shapes оформляй несколькими строками; nullable scalar
null | stringостаётся компактным. Для повторяемого shape используй named type. - Последний необязательный аргумент —
accountId?: string. Required аргумент перед следующим required параметром может сохранятьT | undefined. - Helpers и действия размещай по UI ownership; перенос не меняет null/zero, validation, recovery, closures и hook ordering.
Hooks и derived state
Hooks вызываются без условий и ранних выходов перед ними; custom hook нужен
связному поведению, а не новому имени над одним вызовом. Derived value вычисляй
при render/в VM. Пользовательское действие обрабатывай handler; useEffect
оставляй синхронизации с внешней системой с корректным cleanup/dependencies.
useMemo, useCallback, memo нужны измеренной стоимости или конкретному
контракту стабильной identity; не добавляй их ко всем значениям/handlers.
React Compiler включён в Vite, но не доказывает выигрыш и не заменяет effect
correctness. Не удаляй существующую memoization без понимания её consumers.
Container/VM/view и state owners — в UI.
Domain literals and magic values
Общее правило ownership и символических значений —
Domain values.
Backend vocabulary бери из generated paths; generated artifacts вручную не меняй.
Для открытых string полей допускается локальный enum известных значений,
используемых UI. Он не закрывает wire contract и сохраняет unknown fallback.
Если generator предоставляет runtime enum, используй его.
ProblemDetailsDto.code сейчас string. ApiErrorCode перечисляет известные UI коды, а не закрывает wire contract.
apiErrorCode сохраняет произвольную строку; isApiErrorCode проверяет известное
значение без cast и сохраняет fallback для неизвестного кода. Повторяющуюся
обработку своди у ответственного owner; errors.
@typescript-eslint/no-magic-numbers — error; fixtures/tests/stories исключены
из этой дополнительной проверки. Policy получает имя и единицы; подавление допустимо для
incidental value с объяснением. Обычный UI-текст не превращай в constant:
его owner — i18n.
no-restricted-syntax запрещает inline machine codes и protocol values в production;
no-unsafe-enum-comparison проверяет сравнения enum. Fixtures/stories сохраняют
literal wire values. Новые vocabularies и props profile требуют review.
Проверка
npm run typecheck и npm run lint; behavior проверяй по
Testing, placement — по FSD.