Введение
TypeScript strict mode включает набор опций компилятора, которые обеспечивают максимальную type safety. Хотя это требует больше усилий при написании кода, преимущества в долгосрочной перспективе огромны.
В ExtTeam мы используем TypeScript strict mode во всех enterprise проектах на Nuxt, что позволяет отлавливать баги на этапе компиляции, улучшать refactoring опыт и повышать качество кода.
Что включает Strict Mode?
Включение strict: true в tsconfig.json активирует следующие опции:
- noImplicitAny — запрещает неявный any тип
- strictNullChecks — null и undefined как отдельные типы
- strictFunctionTypes — строгая проверка типов функций
- strictBindCallApply — строгая типизация bind, call, apply
- strictPropertyInitialization — обязательная инициализация свойств класса
- noImplicitThis — запрет неявного this
- alwaysStrict — добавление "use strict" в каждый файл
Настройка в Nuxt 4
Nuxt 4 поддерживает strict mode из коробки:
// nuxt.config.ts
export default defineNuxtConfig({
typescript: {
strict: true,
typeCheck: true // Проверка типов при сборке
}
})Конфигурация tsconfig.json:
{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true
}
}Типизация Composables
Composables должны быть полностью типизированы:
// composables/useUser.ts
import type { Ref } from 'vue'
interface User {
id: string
name: string
email: string
role: 'admin' | 'user' | 'guest'
}
interface UseUserReturn {
user: Ref<User | null>
isAuthenticated: Ref<boolean>
login: (email: string, password: string) => Promise<void>
logout: () => Promise<void>
}
export const useUser = (): UseUserReturn => {
const user = ref<User | null>(null)
const isAuthenticated = computed(() => user.value !== null)
const login = async (email: string, password: string): Promise<void> => {
const response = await $fetch<User>('/api/auth/login', {
method: 'POST',
body: { email, password }
})
user.value = response
}
const logout = async (): Promise<void> => {
await $fetch('/api/auth/logout', { method: 'POST' })
user.value = null
}
return {
user: readonly(user),
isAuthenticated: readonly(isAuthenticated),
login,
logout
}
}Типизация Pages
Страницы Nuxt должны типизировать props и data:
// pages/projects/[slug].vue
<script setup lang="ts">
import type { DetailedProject } from '~/types/ui'
interface Props {
slug: string
}
const props = defineProps<Props>()
// useFetch с типизацией
const { data: project, error } = await useFetch<DetailedProject>(
`/api/projects/${props.slug}`,
{
key: `project-${props.slug}`
}
)
// Проверка на null (strictNullChecks)
if (!project.value) {
throw createError({
statusCode: 404,
statusMessage: 'Project not found'
})
}
</script>Type-safe API Calls
Все API вызовы должны быть типизированы:
// types/api.ts
export interface ApiResponse<T> {
data: T
status: 'success' | 'error'
message?: string
}
export interface CreateProjectRequest {
title: string
description: string
tags: string[]
}
export interface Project {
id: string
title: string
slug: string
description: string
createdAt: string
}
// utils/api.ts
export const api = {
projects: {
create: (data: CreateProjectRequest) =>
$fetch<ApiResponse<Project>>('/api/projects', {
method: 'POST',
body: data
}),
getById: (id: string) =>
$fetch<ApiResponse<Project>>(`/api/projects/${id}`),
list: (params?: { page?: number; limit?: number }) =>
$fetch<ApiResponse<Project[]>>('/api/projects', {
params
})
}
}Миграция на Strict Mode
Постепенная миграция legacy проекта на strict mode:
- Включите strict: false, но добавьте отдельные опции по одной
- Начните с noImplicitAny — самая полезная опция
- Исправьте ошибки в shared/types и utils
- Затем включите strictNullChecks
- Постепенно мигрируйте composables и components
- Используйте @ts-ignore только как временное решение
- После полной миграции включите strict: true
Пример поэтапной миграции tsconfig.json:
// Этап 1: noImplicitAny
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true
}
}
// Этап 2: + strictNullChecks
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true,
"strictNullChecks": true
}
}
// Финал: full strict
{
"compilerOptions": {
"strict": true
}
}Общие проблемы и решения
Проблема: Optional chaining и nullish coalescing
// ❌ Плохо: может быть null
const name = user.name
// ✅ Хорошо: безопасный доступ
const name = user?.name ?? 'Guest'
// ✅ Type guard
if (user?.name) {
console.log(user.name.toUpperCase())
}Проблема: Type narrowing для union types
type Status = 'loading' | 'success' | 'error'
// ❌ Ошибка: Property 'data' does not exist
function handleStatus(status: Status, data: any) {
if (status === 'success') {
return data.value
}
}
// ✅ Правильно: Type narrowing
type LoadingState = { status: 'loading' }
type SuccessState = { status: 'success'; data: any }
type ErrorState = { status: 'error'; error: string }
type State = LoadingState | SuccessState | ErrorState
function handleState(state: State) {
if (state.status === 'success') {
return state.data // TypeScript знает, что это SuccessState
}
}Best Practices
- Создавайте типы в централизованных файлах (types/)
- Используйте interface для объектов, type для unions/intersections
- Предпочитайте readonly для immutable данных
- Используйте Utility Types (Partial, Pick, Omit, Record)
- Избегайте any — используйте unknown для неизвестных типов
- Применяйте Type Guards для сужения типов
- Документируйте сложные типы JSDoc комментариями
- Используйте satisfies оператор для проверки соответствия типу
Performance Implications
Strict mode не влияет на runtime производительность — весь TypeScript код компилируется в обычный JavaScript. Однако:
- Время компиляции может увеличиться на 10-20%
- typeCheck: true в nuxt.config замедляет dev сборку
- Используйте vue-tsc --noEmit для проверки типов отдельно
- В production strict mode не влияет на скорость выполнения
Заключение
TypeScript strict mode — must-have для enterprise Nuxt проектов. Хотя начальные затраты времени выше, long-term выгоды в виде меньшего количества багов, лучшего refactoring опыта и улучшенной документации кода полностью их оправдывают.
В ExtTeam мы не представляем разработку без strict mode — это наш стандарт качества для всех новых проектов.
