Nuxt.js TypeScript集成 #
一、TypeScript配置 #
1.1 自动生成配置 #
Nuxt 自动生成 tsconfig.json,无需手动配置。
1.2 扩展配置 #
tsconfig.json:
json
{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noUncheckedIndexedAccess": true
}
}
1.3 类型检查 #
bash
npx nuxi typecheck
二、类型定义 #
2.1 全局类型 #
types/index.d.ts:
typescript
interface User {
id: number
name: string
email: string
role: 'admin' | 'user' | 'guest'
avatar?: string
createdAt: string
updatedAt: string
}
interface Post {
id: number
title: string
content: string
excerpt: string
slug: string
author: User
tags: string[]
status: 'draft' | 'published'
publishedAt?: string
createdAt: string
updatedAt: string
}
2.2 API类型 #
types/api.d.ts:
typescript
interface ApiResponse<T> {
data: T
message?: string
pagination?: {
page: number
pageSize: number
total: number
totalPages: number
}
}
interface ApiError {
statusCode: number
message: string
errors?: Record<string, string[]>
}
type AsyncDataResult<T> = {
data: Ref<T | null>
pending: Ref<boolean>
error: Ref<Error | null>
refresh: () => Promise<void>
}
2.3 运行时配置类型 #
types/runtime-config.d.ts:
typescript
declare module 'nuxt/schema' {
interface RuntimeConfig {
jwtSecret: string
databaseUrl: string
public: {
apiBase: string
siteName: string
siteUrl: string
}
}
}
export {}
三、组件类型 #
3.1 Props类型 #
vue
<script setup lang="ts">
interface Props {
title: string
subtitle?: string
count: number
items: string[]
config: {
theme: 'light' | 'dark'
size: 'small' | 'medium' | 'large'
}
onClose?: () => void
}
const props = withDefaults(defineProps<Props>(), {
subtitle: '',
count: 0,
items: () => []
})
</script>
3.2 Emits类型 #
vue
<script setup lang="ts">
interface Emits {
(e: 'update', value: string): void
(e: 'delete', id: number): void
(e: 'change', event: Event): void
}
const emit = defineEmits<Emits>()
const handleUpdate = () => {
emit('update', 'new value')
}
</script>
3.3 插槽类型 #
vue
<script setup lang="ts">
interface SlotProps {
item: Post
index: number
isSelected: boolean
}
</script>
<template>
<div>
<slot name="item" :item="item" :index="index" :isSelected="isSelected">
{{ item.title }}
</slot>
</div>
</template>
3.4 泛型组件 #
vue
<script setup lang="ts" generic="T extends { id: number }">
interface Props {
items: T[]
selectedId?: number
}
const props = defineProps<Props>()
const selectedItem = computed(() =>
props.items.find(item => item.id === props.selectedId)
)
</script>
四、组合式函数类型 #
4.1 返回类型 #
typescript
interface UseAuthReturn {
user: Ref<User | null>
token: Ref<string | null>
isAuthenticated: ComputedRef<boolean>
isLoading: ComputedRef<boolean>
login: (credentials: LoginCredentials) => Promise<void>
logout: () => Promise<void>
fetchUser: () => Promise<void>
}
export const useAuth = (): UseAuthReturn => {
const user = useState<User | null>('user', () => null)
const token = useCookie('token')
const isAuthenticated = computed(() => !!user.value && !!token.value)
const isLoading = ref(false)
const login = async (credentials: LoginCredentials) => {
isLoading.value = true
try {
const { data } = await useFetch<LoginResponse>('/api/auth/login', {
method: 'POST',
body: credentials
})
if (data.value) {
user.value = data.value.user
token.value = data.value.token
}
} finally {
isLoading.value = false
}
}
const logout = async () => {
await useFetch('/api/auth/logout')
user.value = null
token.value = null
}
const fetchUser = async () => {
const { data } = await useFetch<User>('/api/auth/me')
user.value = data.value
}
return {
user,
token,
isAuthenticated,
isLoading,
login,
logout,
fetchUser
}
}
4.2 选项类型 #
typescript
interface UseFetchOptions<T> {
immediate?: boolean
lazy?: boolean
server?: boolean
transform?: (data: T) => T
default?: () => T
}
export const useApiFetch = <T>(
url: string,
options: UseFetchOptions<T> = {}
) => {
const { immediate = true, lazy = false, server = true } = options
return useFetch<T>(url, {
immediate,
lazy,
server,
...options
})
}
五、API类型 #
5.1 服务端类型 #
typescript
import { z } from 'zod'
const createPostSchema = z.object({
title: z.string().min(1).max(200),
content: z.string().min(1),
tags: z.array(z.string()).optional(),
status: z.enum(['draft', 'published']).default('draft')
})
type CreatePostInput = z.infer<typeof createPostSchema>
export default defineEventHandler(async (event) => {
const body = await readValidatedBody(event, createPostSchema.parse)
const post = await createPost(body)
return { post }
})
5.2 响应类型 #
typescript
interface PostResponse extends ApiResponse<Post> {}
interface PostListResponse extends ApiResponse<Post[]> {
pagination: {
page: number
pageSize: number
total: number
totalPages: number
}
}
export default defineEventHandler(async (event): Promise<PostListResponse> => {
const query = getQuery(event)
const { posts, total } = await fetchPosts(query)
return {
data: posts,
pagination: {
page: Number(query.page) || 1,
pageSize: Number(query.pageSize) || 10,
total,
totalPages: Math.ceil(total / (Number(query.pageSize) || 10))
}
}
})
六、类型工具 #
6.1 类型守卫 #
typescript
function isUser(value: unknown): value is User {
return (
typeof value === 'object' &&
value !== null &&
'id' in value &&
'name' in value &&
'email' in value
)
}
const data: unknown = await fetchData()
if (isUser(data)) {
console.log(data.name)
}
6.2 类型断言 #
typescript
const route = useRoute()
const id = route.params.id as string
const page = Number(route.query.page) as number
6.3 类型提取 #
typescript
type UserKeys = keyof User
type UserRole = User['role']
type OptionalUserFields = Partial<User>
type RequiredUserFields = Required<User>
七、严格模式 #
7.1 启用严格模式 #
tsconfig.json:
json
{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedIndexedAccess": true
}
}
7.2 处理可能为null的值 #
typescript
const user = useState<User | null>('user')
if (user.value) {
console.log(user.value.name)
}
const name = user.value?.name ?? 'Guest'
八、类型导入 #
8.1 导入类型 #
typescript
import type { User, Post } from '~/types'
const user = ref<User | null>(null)
const posts = ref<Post[]>([])
8.2 自动导入类型 #
Nuxt 自动导入 types/ 目录下的类型。
九、最佳实践 #
9.1 类型优先 #
typescript
type Status = 'pending' | 'approved' | 'rejected'
interface Task {
id: number
title: string
status: Status
}
const updateStatus = (task: Task, status: Status) => {
task.status = status
}
9.2 避免any #
typescript
const data: any = fetchData()
const data: unknown = fetchData()
if (isExpectedType(data)) {
process(data)
}
9.3 使用泛型 #
typescript
interface ApiResponse<T> {
data: T
message: string
}
const fetchUser = async (): Promise<ApiResponse<User>> => {
return await $fetch('/api/user')
}
const fetchPosts = async (): Promise<ApiResponse<Post[]>> => {
return await $fetch('/api/posts')
}
十、总结 #
本章介绍了 Nuxt.js TypeScript 集成:
- TypeScript 配置
- 类型定义
- 组件类型
- 组合式函数类型
- API 类型
- 类型工具
- 严格模式
- 最佳实践
TypeScript 可以显著提升代码质量和开发体验,下一章我们将学习测试策略。
最后更新:2026-03-28