Учебник веб-разработки
Разделы учебника
На этой странице

X. Инструменты и проверки

Лаборатория: типы, линтер, формат, runtime-вход и поведение

Оглавление · Инструменты · Проверки проекта

Задача: предсказать, какую ошибку заметит инструмент, затем получить конкретное свидетельство. Нужны TypeScript, схемы и функции.

Разные вопросы

СредствоЧто проверяетЧего не доказывает
TypecheckСогласованность с типами и configРеальные неизвестные значения и бизнес-результат
OxlintВключённые правила анализаПолную корректность программы
OxfmtПринятую запись текстаВерный смысл вычисления
ZodКонкретное значение по схемеИнварианты, не выраженные в схеме
ТестУтверждение на заданном сценарииВсе возможные входы и реальную зависимость вместо mock

Oxlint и Oxfmt имеют разные задачи. У проекта в .oxlintrc включены plugins typescript/react/nextjs и категория correctness=error; root lint работает по apps и packages с --deny-warnings. Oxfmt имеет отдельный ignore list. Check проверяет формат, обычный запуск пишет файлы; после записи прочитайте diff.

Подготовка временных файлов

Все команды ниже — из корня своего worktree, после штатной установки workspace. Создайте apps/web/.local/tooling-lesson и пять файлов из следующих блоков. .local исключён из Git; это не место для постоянных исходников. Импорт Zod будет разрешаться через зависимости web. После упражнения удалите только созданные файлы и пустой каталог урока.

1. type-error.mts

const count: number = "3";
console.log(count);
pnpm --filter @atmanki/web exec tsc --ignoreConfig --noEmit --strict \
  --skipLibCheck --types node --target es2022 --module nodenext \
  .local/tooling-lesson/type-error.mts
node apps/web/.local/tooling-lesson/type-error.mts

Компилятор должен сообщить несовместимость string и number. Node напечатает 3: аннотация удаляется, значение остаётся строкой. Вывод без кавычек не доказывает, что значение стало числом. --ignoreConfig относится к изолированной пробе TS 7; обычные проверки пакета используют его tsconfig и scripts.

2. lint-error.mts

export function inspectValue(value: number): number {
  debugger;
  return value;
}
pnpm exec oxlint --deny-warnings --deny no-debugger \
  apps/web/.local/tooling-lesson/lint-error.mts

Ожидается диагностика no-debugger. Правило явно включено командой урока; не предполагаем, что оно обязано входить в текущую категорию проекта. Это допустимый JS/TS, но нарушает выбранное правило. Autofix и suppression требуют понимания причины; отключение диагностики не исправляет поведение.

3. format-error.mts

Блок показан как plain text, чтобы форматтер главы сохранил намеренное расхождение.

export const sample={value:1}
pnpm exec oxfmt --check apps/web/.local/tooling-lesson/format-error.mts
pnpm exec oxfmt apps/web/.local/tooling-lesson/format-error.mts
pnpm exec oxfmt --check apps/web/.local/tooling-lesson/format-error.mts

Первый check ожидает расхождение, второй — после форматирования — проходит. Сравните before/after: изменение пробелов и разделителей не делает value другим. В этом блоке исходная запись намеренно не соответствует стилю.

4. runtime-input.mts

import { z } from "zod";
const schema = z.object({ count: z.number().int().nonnegative() });
const input: unknown = { count: "3" };
console.log(schema.safeParse(input).success); // false

Тип unknown корректен, но конкретное значение не проходит runtime-схему. safeParse возвращает результат проверки, не обязано бросать исключение: процесс с выводом false может завершиться с exit code 0. Проверяйте результат, а не только успешность запуска команды.

5. behavior.mts

export function total(values: readonly number[]): number {
  return values.reduce((sum, value) => sum + value, 1);
}

Контракт упражнения: сумма массива, пустой массив даёт 0. Функция компилируется, но ошибочный начальный аккумулятор нарушает контракт. Создайте рядом behavior.test.mts:

import assert from "node:assert/strict";
import { test } from "node:test";
import { total } from "./behavior.mts";

test("sums values and uses zero for an empty input", () => {
  assert.equal(total([2, 3]), 5);
  assert.equal(total([]), 0);
});
node apps/web/.local/tooling-lesson/runtime-input.mts
node --test apps/web/.local/tooling-lesson/behavior.test.mts

Тест должен упасть. Поменяйте начальное значение на 0 и повторите его. Для отдельной typecheck-пробы с импортом .mts добавьте --allowImportingTsExtensions к параметрам выше. Проверка примера через Node test runner не меняет Jest-стек приложения: это временный урок, не новый UI-runner.

Что значит «прошло»

Для каждого файла запишите: команду, включённые правила, exit code, диагностику и наблюдаемый результат. Сравните предсказание с выполнением. Не ожидайте, что каждая ошибка будет обнаружена ровно одним средством: области могут пересекаться.

Изолированные файлы и явные CLI flags проверяют эти примеры. Они не подтверждают, что root scripts включают .local или весь учебный код; сами Markdown code blocks не проходят typecheck автоматически. Отдельные примеры извлекаются и проверяются при подготовке соответствующей главы.

Ежедневный цикл

Исходник схемы
flowchart LR
  Change["Маленькое изменение"] --> Target["Проверки затронутого контракта"]
  Target --> Diff["Чтение diff"]
  Diff --> Commit["Отдельный коммит"]
  Commit --> CI["CI на нужном ref"]
  CI --> Release["Публикация и проверка результата"]

Выбирайте проверки по изменению: ссылки/экспорт для docs, типы и тесты для контрактов, обе поверхности Storybook для компонента. Полный набор не требуется повторять после каждого абзаца; production-образы собирает CI.

Успех редактора, CLI, CI, публикации и живого сценария — разные стадии. Сравнивайте ref, версии, lockfile, переменные и рабочий каталог. Список реальных команд и границ покрытия хранится в главе проверок, расследование симптомов — в разборе проблем.