Vite изначально проектировался как инструмент быстрой разработки, ориентированный на современный стек JavaScript и TypeScript. Однако одна из ключевых особенностей архитектуры Vite заключается в том, что он не выполняет полноценную проверку типов TypeScript во время разработки.
Во время запуска dev-сервера Vite использует сверхбыструю
трансформацию через esbuild, которая отвечает только
за:
Проверка типов (type checking) в этот процесс не
входит.
Именно поэтому в крупных проектах почти всегда используется
отдельный запуск tsc исключительно для
статического анализа типов.
Классический компилятор TypeScript (tsc) выполняет:
Все эти операции относительно тяжёлые.
Vite делает ставку на скорость dev-сервера, поэтому TypeScript в Vite работает иначе:
// app.ts
const value: number = 'hello'
Даже при наличии ошибки приложение может успешно запускаться.
esbuild просто удалит типы:
const value = 'hello'
Ошибку типов покажет только:
tsc;В экосистеме Vite принято разделять две задачи:
| Задача | Инструмент |
|---|---|
| Трансформация TS → JS | esbuild |
| Проверка типов | tsc |
Такое разделение даёт несколько преимуществ:
Проверка типов не блокирует обновление модулей.
Типизация может выполняться:
Крупные проекты с тысячами файлов работают быстрее.
tscНаиболее распространённый вариант:
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build"
}
}
Здесь:
tsc выполняет проверку типов.vite build выполняет production-сборку.Если TypeScript обнаружит ошибку:
const userId: number = 'admin'
сборка остановится:
Type 'string' is not assignable to type 'number'
Обычно Vite не использует tsc для генерации
JavaScript.
Поэтому применяется режим:
tsc --noEmit
Он означает:
.d.ts;Пример:
{
"scripts": {
"typecheck": "tsc --noEmit"
}
}
noEmit
считается стандартомVite уже выполняет сборку самостоятельно.
Если не использовать noEmit, TypeScript начнёт
генерировать:
.js;.map;.d.ts.Это приводит к:
Поэтому типичная конфигурация Vite-проекта выглядит так:
{
"compilerOptions": {
"noEmit": true
}
}
Отдельная проверка типов часто запускается параллельно с dev-сервером.
Например:
{
"scripts": {
"dev": "vite",
"typecheck": "tsc --noEmit --watch"
}
}
Тогда:
tsc непрерывно следит за типами.Команда:
tsc --watch
или:
tsc -w
запускает компилятор в режиме отслеживания изменений.
При изменении файлов TypeScript автоматически:
Пример вывода:
Found 0 errors. Watching for file changes.
После ошибки:
src/api.ts:12:7 - error TS2322
Часто используется пакет concurrently.
Установка:
npm install concurrently -D
Скрипт:
{
"scripts": {
"dev": "concurrently \"vite\" \"tsc --noEmit --watch\""
}
}
Теперь:
Иногда разработчики отключают постоянную проверку типов ради максимальной скорости разработки.
Тогда используется схема:
{
"scripts": {
"build": "tsc --noEmit && vite build"
}
}
Ошибки появляются только при production build.
vite build и tscЭто фундаментальное различие.
vite buildОтвечает за:
tscОтвечает за:
vite build может успешно завершиться при ошибках типовПример:
function sum(a: number, b: number) {
return a + b
}
sum('1', '2')
Vite соберёт проект успешно.
Причина:
vue-tscВ проектах на Vue стандартный tsc не способен корректно
анализировать .vue-файлы.
Поэтому используется:
vue-tsc --noEmit
Пример:
{
"scripts": {
"typecheck": "vue-tsc --noEmit"
}
}
В React-проектах обычно достаточно стандартного:
tsc --noEmit
Поскольку:
.tsx анализируется нативно.TypeScript поддерживает инкрементальную проверку.
Настройка:
{
"compilerOptions": {
"incremental": true
}
}
После первого запуска создаётся:
.tsbuildinfo
Он хранит:
Повторные проверки становятся значительно быстрее.
В монорепозиториях часто используется:
{
"compilerOptions": {
"composite": true
}
}
Это необходимо для:
Крупные Vite-проекты могут состоять из нескольких TypeScript-пакетов.
Структура:
packages/
ui/
core/
api/
Каждый пакет содержит собственный tsconfig.json.
Главный конфиг:
{
"references": [
{ "path": "./packages/ui" },
{ "path": "./packages/core" },
{ "path": "./packages/api" }
]
}
Проверка:
tsc --build
--buildФлаг:
tsc --build
или:
tsc -b
предназначен для:
TypeScript анализирует зависимости между пакетами и пересобирает только изменённые части.
При разработке библиотек часто требуется:
{
"compilerOptions": {
"declaration": true
}
}
Тогда TypeScript создаёт:
dist/index.d.ts
Однако даже в этом случае Vite обычно отвечает только за JS-сборку.
Типичная схема:
{
"scripts": {
"build": "tsc && vite build"
}
}
Где:
tsc генерирует типы;Во многих проектах типизация проверяется отдельно от сборки.
Пример GitHub Actions:
- run: npm run typecheck
- run: npm run build
Это позволяет:
tscDev-сервер работает, хотя типизация уже сломана.
Например:
type ApiResponse<T> = {
data: T
}
const response: ApiResponse<number> = {
data: 'error'
}
Без tsc ошибка может остаться незамеченной.
Особенно критично для:
vite-plugin-checkerСуществует плагин:
npm install vite-plugin-checker -D
Конфигурация:
import checker from 'vite-plugin-checker'
export default defineConfig({
plugins: [
checker({
typescript: true
})
]
})
Плагин:
tsc параллельно;vite-plugin-checkerАрхитектурно плагин:
Главное преимущество:
Основная философия Vite:
Полноценный tsc значительно ухудшил бы скорость старта
крупных проектов.
esbuild против tscesbuild написан на Go и оптимизирован под:
TypeScript compiler написан на TypeScript и ориентирован прежде всего на:
Распространённый вариант:
{
"scripts": {
"dev": "vite",
"typecheck": "tsc --noEmit",
"typecheck:watch": "tsc --noEmit --watch",
"build": "tsc --noEmit && vite build"
}
}
Иногда создаётся:
tsconfig.typecheck.json
Пример:
{
"extends": "./tsconfig.json",
"include": ["src"]
}
Запуск:
tsc --project tsconfig.typecheck.json --noEmit
Это позволяет:
Для ускорения проверки используются:
{
"exclude": [
"dist",
"node_modules",
"coverage"
]
}
Также иногда исключаются:
Даже JS-проект Vite может использовать type checking.
Настройка:
{
"compilerOptions": {
"checkJs": true,
"allowJs": true
}
}
Теперь TypeScript анализирует:
/**
* @param {number} id
*/
function load(id) {}
load('admin')
TypeScript предоставляет подробные диагностические сообщения.
Например:
tsc --pretty
или:
tsc --extendedDiagnostics
Последний режим показывает:
skipLibCheckДля ускорения проектов часто включается:
{
"compilerOptions": {
"skipLibCheck": true
}
}
Это отключает проверку типов внутри declaration-файлов зависимостей.
Преимущества:
Недостаток:
Наиболее распространённая архитектура выглядит так:
Vite → transpilation
IDE → type hints
tsc --watch → type checking
tsc --noEmit
↓
vite build
lint
↓
typecheck
↓
tests
↓
build