类型系统概览
介绍
RuoYi-Plus-UniApp 前端项目采用 TypeScript 构建完整的类型系统,通过全局类型声明、模块扩展和工具类型,提供端到端的类型安全保障。类型系统涵盖 API 交互、UI 组件、路由管理、状态管理等所有核心模块,确保代码质量和开发体验。
核心特性:
- 全局类型声明 - 通用类型全局可用,无需频繁导入
- 模块类型扩展 - 扩展第三方库类型定义,增强类型安全
- 严格类型检查 - 启用 TypeScript 严格模式,杜绝类型漏洞
- 自动类型生成 - 自动生成组件、图标、导入等类型定义
- 智能类型推导 - 充分利用 TypeScript 类型推导能力
- 泛型类型支持 - 支持泛型组件和函数,实现灵活的类型复用
- 类型文档完善 - 所有类型都有详细的 JSDoc 注释说明
- 开发工具集成 - 与 VSCode、Vite、ESLint 深度集成
本文档提供类型系统的整体架构说明、类型分类介绍、使用规范和最佳实践。
类型系统架构
核心类型文件结构
src/types/
├── global.d.ts # 全局类型定义 (API、分页、UI 等)
├── router.d.ts # Vue Router 类型扩展
├── http.d.ts # HTTP 请求和响应类型
├── icons.d.ts # 图标类型 (自动生成)
├── components.d.ts # 组件类型 (自动生成)
├── auto-imports.d.ts # 自动导入类型 (自动生成)
├── element.d.ts # Element Plus 类型扩展
└── env.d.ts # 环境变量和 Vite 类型类型文件说明
global.d.ts - 全局类型定义
全局类型文件定义了项目中最常用的类型,这些类型在任何地方都可以直接使用,无需导入。
主要内容:
- API 交互类型 (
Result<T>,R<T>,PageResult<T>,PageQuery) - UI 控制类型 (
DialogState,FieldConfig,DictItem) - 响应式类型 (
SpanType,ResponsiveSpan) - 组件实例类型 (
ComponentInternalInstance)
设计原则:
- 全局可用 - 避免频繁 import
- 类型安全 - 为核心功能提供类型保障
- 统一标准 - 确保类型定义一致
- 易于维护 - 集中管理通用类型
router.d.ts - 路由类型扩展
扩展 Vue Router 的类型定义,添加项目特定的路由元数据和属性。
主要内容:
RouteMeta- 路由元数据扩展_RouteRecordBase- 路由记录扩展TagView- 多标签页视图类型
http.d.ts - HTTP 类型定义
定义 HTTP 请求和响应的类型,包括自定义请求头、拦截器等。
主要内容:
CustomHeaders- 自定义请求头HttpConfig- HTTP 配置选项- 请求拦截器和响应拦截器类型
icons.d.ts - 图标类型 (自动生成)
由构建工具自动生成的图标类型定义,包含所有可用图标的名称。
特点:
- 自动生成 - 扫描图标文件自动生成类型
- 类型安全 - 使用图标时有完整的类型提示
- 支持多种图标库 - Font Icon、UnoCSS Icon
components.d.ts - 组件类型 (自动生成)
由 unplugin-vue-components 自动生成,包含所有注册组件的类型定义。
特点:
- 自动注册 - 无需手动导入组件
- 类型推导 - 自动推导组件 Props 和 Emits
- 全局可用 - 所有组件全局类型提示
auto-imports.d.ts - 自动导入类型 (自动生成)
由 unplugin-auto-import 自动生成,包含自动导入的 API 类型定义。
特点:
- Vue API - ref, reactive, computed, watch 等
- Vue Router API - useRouter, useRoute 等
- Pinia API - defineStore, storeToRefs 等
- 自定义 Composables - useAuth, useDict 等
element.d.ts - Element Plus 扩展
扩展 Element Plus 组件库的类型定义。
主要内容:
ElTagType- Element Tag 组件类型- 组件 Props 类型增强
- 组件事件类型增强
env.d.ts - 环境变量类型
定义环境变量和 Vite 特定类型。
主要内容:
ImportMetaEnv- 环境变量接口- Vite 静态资源类型
- 模块声明
类型分类详解
1. API 交互类型
API 交互类型定义了前后端数据交互的标准格式,确保类型安全和一致性。
Result<T> - 统一响应格式
所有 API 请求都返回 Result<T> 类型,使用 await-to-js 模式处理错误。
/**
* 统一 API 响应类型
* @description 定义所有 API 请求的统一返回格式 [错误, 数据]
* @template T 响应数据的类型
*/
declare type Result<T = any> = Promise<[Error | null, T | null]>使用示例:
// API 函数定义
export const getUserInfo = (): Result<UserVo> => {
return http.get<UserVo>('/system/user/getInfo')
}
// 组件中使用
const [err, data] = await getUserInfo()
if (!err && data) {
userInfo.value = data
} else {
console.error('获取用户信息失败:', err)
}优点:
- 显式错误处理 - 强制处理错误情况
- 类型安全 - TypeScript 自动推导数据类型
- 代码简洁 - 避免 try-catch 嵌套
R<T> - 标准 API 响应
后端返回的标准响应结构,包含状态码、消息和数据。
/**
* 标准 API 响应结构
* @description 后端返回的标准响应格式,包含状态码、消息和数据
* @template T 数据字段的类型
*/
declare interface R<T = any> {
/** 响应状态码 */
code: number
/** 响应消息 */
msg: string
/** 响应数据 */
data: T
}使用场景:
- HTTP 拦截器中处理响应
- 需要直接访问状态码和消息时
- 自定义错误处理逻辑
PageResult<T> - 分页响应
标准化的分页数据结构,与后端 PageResult 保持一致。
/**
* 分页响应数据类型
* @description 标准化的分页数据结构,与后端 PageResult 保持一致
* @template T 列表项的类型
*/
declare interface PageResult<T = any> {
/** 数据记录列表 */
records: T[]
/** 总记录数 */
total: number
/** 总页数 */
pages: number
/** 当前页码 */
current: number
/** 每页大小 */
size: number
/** 是否为最后一页 */
last: boolean
}使用示例:
// API 函数定义
export const pageUsers = (query?: UserQuery): Result<PageResult<UserVo>> => {
return http.get<PageResult<UserVo>>('/system/user/list', query)
}
// 组件中使用
const tableData = ref<UserVo[]>([])
const total = ref(0)
const loadData = async () => {
const [err, data] = await pageUsers(queryParams.value)
if (!err && data) {
tableData.value = data.records
total.value = data.total
}
}PageQuery - 分页查询参数
用于后端分页查询的通用参数接口。
/**
* 分页查询基础参数
* @description 用于后端分页查询的通用参数接口
*/
declare interface PageQuery {
/** 当前页码,从1开始 */
pageNum?: number
/** 每页显示记录数 */
pageSize?: number
/** 排序字段 */
orderByColumn?: string
/** 排序方向 asc/desc */
isAsc?: string
/** 模糊搜索关键词 */
searchValue?: string
/** 扩展查询参数 */
params?: Record<string, any>
}使用示例:
// 定义查询参数接口,继承 PageQuery
interface UserQuery extends PageQuery {
userName?: string
status?: string
deptId?: number
}
// 组件中使用
const queryParams = ref<UserQuery>({
pageNum: 1,
pageSize: 10,
userName: '',
status: ''
})
const handleQuery = () => {
loadData()
}2. UI 控制类型
UI 控制类型用于管理界面元素的状态和配置。
DialogState - 弹窗状态
用于管理弹窗的显示状态和基本属性。
/**
* 弹窗状态配置
* @description 用于管理弹窗的显示状态和基本属性
*/
declare interface DialogState {
/** 弹窗标题 */
title?: string
/** 弹窗是否显示 */
visible: boolean
}使用示例:
const dialog = reactive<DialogState>({
title: '',
visible: false
})
const handleAdd = () => {
dialog.title = '新增用户'
dialog.visible = true
}
const handleEdit = (row: UserVo) => {
dialog.title = '编辑用户'
dialog.visible = true
}DictItem - 字典项
用于下拉选择、标签等组件的选项数据,支持 Element Plus 标签样式。
/**
* 字典项配置
* @description 用于下拉选择、标签等组件的选项数据,支持 Element Plus 标签样式
*/
declare interface DictItem {
/** 显示标签文本 */
label: string
/** 实际存储的值 */
value: string
/** 状态标识 */
status?: string
/** Element Plus Tag 组件的类型 */
elTagType?: ElTagType
/** Element Plus Tag 组件的自定义类名 */
elTagClass?: string
}使用示例:
// 定义字典选项
const statusOptions = ref<DictItem[]>([
{ label: '正常', value: '0', elTagType: 'success' },
{ label: '停用', value: '1', elTagType: 'danger' }
])
// 下拉选择使用
<el-select v-model="form.status">
<el-option
v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
// 标签显示使用
<el-tag :type="dict.elTagType">{{ dict.label }}</el-tag>FieldConfig - 字段配置
用于详情展示、表单等组件的字段配置,支持多种显示类型和自定义渲染。
/**
* 字段配置接口
* @description 用于详情展示、表单等组件的字段配置,支持多种显示类型和自定义渲染
*/
declare interface FieldConfig {
/** 字段属性名,支持嵌套如 'user.name' */
prop: string
/** 字段显示标签 */
label: string
/** 字段占用列数 */
span?: number
/** 自定义插槽名称,用于自定义渲染 */
slot?: string
/** 自定义格式化函数 */
formatter?: (value: any, data: any) => string
/** 数据类型,用于自动格式化 */
type?: 'text' | 'copyable' | 'date' | 'datetime' | 'currency' | 'boolean' | 'array' | 'dict' | 'image' | 'password' | 'html' | 'file'
/** 字典选项,当type为dict时使用 */
dictOptions?: DictItem[]
/** 图片预览配置,当type为image时使用 */
imageConfig?: {
width?: number | string
height?: number | string
showAll?: boolean
layout?: 'flex' | 'grid'
columns?: number
maxShow?: number
gap?: number
}
/** 是否隐藏字段,支持函数动态判断 */
hidden?: boolean | ((data: any) => boolean)
/** 分组名称,设置后会按组分块显示 */
group?: string
/** 是否不参与打印,设为true时该字段不会在打印中显示 */
noPrint?: boolean
}使用示例:
const detailFields: FieldConfig[] = [
{ prop: 'userName', label: '用户名', type: 'text' },
{ prop: 'email', label: '邮箱', type: 'copyable' },
{ prop: 'status', label: '状态', type: 'dict', dictOptions: statusOptions.value },
{ prop: 'createTime', label: '创建时间', type: 'datetime' },
{
prop: 'avatar',
label: '头像',
type: 'image',
imageConfig: { width: 100, height: 100 }
}
]FieldVisibilityConfig - 字段可见性
用于控制界面字段的显示/隐藏状态,支持层级结构。
/**
* 字段可见性配置
* @description 用于控制界面字段的显示/隐藏状态,支持层级结构
*/
declare interface FieldVisibilityConfig {
/** 字段唯一标识 */
key: string | number
/** 字段名称 */
field: string
/** 字段显示标签 */
label: string
/** 是否可见 */
visible: boolean
/** 子字段配置,支持层级结构 */
children?: Array<FieldVisibilityConfig>
}3. 响应式类型
响应式类型用于支持不同屏幕尺寸下的自适应布局。
SpanType - 响应式栅格类型
支持固定数字、响应式对象或自动模式的栅格跨度类型。
/**
* Span 属性类型
* @description 支持固定数字、响应式对象或自动模式
*/
declare type SpanType = number | ResponsiveSpan | 'auto' | undefinedResponsiveSpan - 响应式配置
用于栅格布局的响应式配置,支持不同屏幕尺寸下的列数设置。
/**
* 响应式 Span 配置接口
* @description 用于栅格布局的响应式配置,支持不同屏幕尺寸下的列数设置
*/
declare interface ResponsiveSpan {
/** 超小屏幕 <768px */
xs?: number
/** 小屏幕 ≥768px */
sm?: number
/** 中等屏幕 ≥992px */
md?: number
/** 大屏幕 ≥1200px */
lg?: number
/** 超大屏幕 ≥1920px */
xl?: number
}使用示例:
// 固定跨度
<AFormInput label="用户名" v-model="form.userName" :span="12" />
// 预设响应式
<AFormInput label="邮箱" v-model="form.email" span="auto" />
// 自定义响应式
<AFormInput
label="手机号"
v-model="form.phone"
:span="{ xs: 24, sm: 24, md: 12, lg: 8, xl: 6 }"
/>4. 路由类型
路由类型扩展了 Vue Router 的类型定义,添加了项目特定的元数据和属性。
RouteMeta - 路由元数据扩展
declare module 'vue-router' {
interface RouteMeta {
/** 路由标题 */
title?: string
/** 路由图标 */
icon?: IconCode
/** 是否固定在标签页 */
affix?: boolean
/** 是否缓存页面 */
noCache?: boolean
/** 激活的菜单路径 */
activeMenu?: string
/** 是否显示面包屑 */
breadcrumb?: boolean
/** 国际化键名 */
i18nKey?: string
/** 外链地址 */
link?: string
}
}_RouteRecordBase - 路由记录扩展
declare module 'vue-router' {
interface _RouteRecordBase {
/** 是否隐藏菜单 */
hidden?: boolean | string | number
/** 权限标识数组 */
permissions?: string[]
/** 角色数组 */
roles?: string[]
/** 总是显示根路由 */
alwaysShow?: boolean
/** 默认查询参数 */
query?: string
/** 父级路径 */
parentPath?: string
}
}TagView - 多标签页类型
declare module 'vue-router' {
interface TagView {
/** 完整路径 */
fullPath?: string
/** 路由名称 */
name?: string
/** 路由路径 */
path?: string
/** 标签标题 */
title?: string
/** 路由元数据 */
meta?: RouteMeta
/** 查询参数 */
query?: LocationQuery
}
}5. 组件类型
组件类型定义了 Vue 组件的 Props、Emits 等接口。
ComponentInternalInstance - 组件实例
/** Vue 组件实例类型 */
declare type ComponentInternalInstance = ComponentInstance使用示例:
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance() as ComponentInternalInstance
const proxy = instance?.proxy6. HTTP 类型
HTTP 类型定义了请求和响应的相关类型。
CustomHeaders - 自定义请求头
/**
* 自定义请求头配置
*/
export interface CustomHeaders {
/** 是否需要认证 */
auth?: boolean
/** 是否需要租户信息 */
tenant?: boolean
/** 是否防止重复提交 */
repeatSubmit?: boolean
}使用示例:
// API 函数中指定自定义请求头
export const login = (data: LoginForm): Result<LoginVo> => {
return http.post<LoginVo>('/auth/login', data, {
auth: false, // 登录接口不需要认证
tenant: true // 需要租户信息
})
}类型声明方式
1. 全局类型声明
使用 declare global 在全局作用域声明类型,无需导入即可使用。
// global.d.ts
declare global {
interface PageResult<T> {
records: T[]
total: number
}
interface DialogState {
title?: string
visible: boolean
}
}
export {} // 确保文件是模块特点:
- ✅ 无需导入,全局可用
- ✅ 适合通用类型
- ⚠️ 避免命名冲突
- ⚠️ 不要滥用全局类型
使用场景:
- API 交互类型 (Result, PageResult)
- UI 控制类型 (DialogState, DictItem)
- 响应式类型 (SpanType, ResponsiveSpan)
2. 模块扩展
扩展第三方库的类型定义,增强类型安全。
// router.d.ts
declare module 'vue-router' {
interface RouteMeta {
title?: string
icon?: IconCode
permissions?: string[]
}
interface _RouteRecordBase {
hidden?: boolean
roles?: string[]
}
}特点:
- ✅ 扩展现有类型
- ✅ 保持类型兼容
- ✅ IDE 智能提示
- ✅ 不影响原有类型
使用场景:
- 扩展 Vue Router 类型
- 扩展 Element Plus 类型
- 扩展 Axios 类型
3. 导出类型
在模块中导出类型供其他模块使用。
// http.d.ts
export interface CustomHeaders {
auth?: boolean
tenant?: boolean
repeatSubmit?: boolean
}
export interface HttpConfig {
baseURL: string
timeout: number
}使用:
import type { CustomHeaders, HttpConfig } from '@/types/http'
const headers: CustomHeaders = {
auth: true,
tenant: true
}特点:
- ✅ 显式导入,清晰明确
- ✅ 避免全局污染
- ✅ 适合模块专用类型
4. 命名空间
使用命名空间组织相关类型。
// api.d.ts
declare namespace API {
interface User {
id: number
name: string
}
interface LoginParams {
username: string
password: string
}
interface LoginResult {
token: string
user: User
}
}使用:
const user: API.User = {
id: 1,
name: '张三'
}
const loginParams: API.LoginParams = {
username: 'admin',
password: '123456'
}类型使用规范
1. 类型导入规范
// ✅ 推荐: 使用 type 关键字导入类型
import type { IconCode } from '@/types/icons'
import type { UserVo } from '@/api/system/user/types'
// ✅ 推荐: 混合导入
import { ref, computed, type Ref, type ComputedRef } from 'vue'
// ✅ 全局类型无需导入
const result: PageResult<UserVo> = {
records: [],
total: 0,
pages: 0,
current: 1,
size: 10,
last: false
}
// ❌ 避免: 默认导入类型
import IconCode from '@/types/icons'
// ❌ 避免: 不使用 type 关键字
import { IconCode } from '@/types/icons'2. 组件 Props 类型
// ✅ 推荐: 使用 interface 定义 Props
interface UserFormProps {
modelValue: UserBo
mode: 'add' | 'edit' | 'view'
disabled?: boolean
}
const props = defineProps<UserFormProps>()
// ✅ 推荐: 使用 withDefaults 提供默认值
const props = withDefaults(defineProps<UserFormProps>(), {
mode: 'add',
disabled: false
})
// ❌ 避免: 使用 type 定义 Props
type UserFormProps = {
modelValue: UserBo
mode: 'add' | 'edit' | 'view'
}
// ❌ 避免: 不定义类型
const props = defineProps({
modelValue: Object,
mode: String
})3. 事件类型定义
// ✅ 推荐: 使用箭头函数语法
const emit = defineEmits<{
'update:modelValue': [value: UserBo]
submit: [data: UserBo]
cancel: []
}>()
// ✅ 可选: 使用接口定义
interface UserFormEmits {
(e: 'update:modelValue', value: UserBo): void
(e: 'submit', data: UserBo): void
(e: 'cancel'): void
}
const emit = defineEmits<UserFormEmits>()
// ❌ 避免: 不定义类型
const emit = defineEmits(['update:modelValue', 'submit', 'cancel'])4. Ref 类型定义
// ✅ 推荐: 自动推导
const count = ref(0) // Ref<number>
const name = ref('') // Ref<string>
// ✅ 推荐: 显式声明复杂类型
const user = ref<UserVo | null>(null)
const list = ref<AdVo[]>([])
const form = ref<UserBo>({} as UserBo)
// ✅ 推荐: 组件实例类型
import type { FormInstance } from 'element-plus'
const formRef = ref<FormInstance>()
// ❌ 避免: 使用 any
const data = ref<any>({})
const result = ref<any>(null)5. Reactive 类型定义
// ✅ 推荐: 自动推导
const state = reactive({
loading: false,
data: [] as UserVo[]
})
// ✅ 推荐: 使用 interface
interface FormState {
name: string
age: number
email: string
}
const form = reactive<FormState>({
name: '',
age: 0,
email: ''
})
// ✅ 推荐: 复杂状态
interface QueryState {
pageNum: number
pageSize: number
params: UserQuery
}
const query = reactive<QueryState>({
pageNum: 1,
pageSize: 10,
params: {}
})6. Computed 类型定义
// ✅ 推荐: 自动推导
const fullName = computed(() => {
return `${user.value.firstName} ${user.value.lastName}`
}) // ComputedRef<string>
// ✅ 推荐: 显式声明
const total = computed<number>(() => {
return list.value.reduce((sum, item) => sum + item.amount, 0)
})
// ✅ 推荐: 可写计算属性
const inputValue = computed<string>({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})7. 函数类型定义
// ✅ 推荐: 显式声明参数和返回类型
function getUser(id: number): Promise<UserVo> {
return http.get<UserVo>(`/system/user/${id}`)
}
// ✅ 推荐: 箭头函数
const handleSubmit = async (data: UserBo): Promise<void> => {
const [err] = await saveUser(data)
if (!err) {
message.success('保存成功')
}
}
// ✅ 推荐: 使用泛型
function getData<T>(url: string): Promise<T> {
return http.get<T>(url)
}
// ❌ 避免: 不声明类型
function getUser(id) {
return http.get(`/system/user/${id}`)
}类型最佳实践
1. 复用业务类型
定义可复用的基础类型,通过继承和组合实现类型复用。
// ✅ 定义基础实体类型
interface BaseEntity {
id?: string | number
createTime?: string
createBy?: string
updateTime?: string
updateBy?: string
}
// ✅ 继承基础类型
interface UserBo extends BaseEntity {
userName: string
email: string
status: string
}
interface UserVo extends BaseEntity {
userName: string
email: string
status: string
statusName: string
deptName: string
}
// ✅ 使用 Omit 排除字段
type UserCreateBo = Omit<UserBo, 'id' | 'createTime' | 'updateTime'>
// ✅ 使用 Pick 选择字段
type UserListItem = Pick<UserVo, 'id' | 'userName' | 'email' | 'status'>2. 类型守卫
使用类型守卫函数进行运行时类型检查。
// ✅ 定义类型守卫函数
function isUserVo(obj: any): obj is UserVo {
return obj && typeof obj.userName === 'string' && typeof obj.email === 'string'
}
function isPageResult<T>(obj: any): obj is PageResult<T> {
return obj && Array.isArray(obj.records) && typeof obj.total === 'number'
}
// ✅ 使用类型守卫
const data: unknown = await fetchData()
if (isUserVo(data)) {
console.log(data.userName) // 类型安全
console.log(data.email) // 类型安全
}
if (isPageResult<UserVo>(data)) {
data.records.forEach(user => {
console.log(user.userName) // 类型安全
})
}3. 泛型约束
使用泛型约束提高类型安全性和灵活性。
// ✅ 约束泛型必须有特定属性
function getProperty<T extends object, K extends keyof T>(
obj: T,
key: K
): T[K] {
return obj[key]
}
// 使用
const user = { name: '张三', age: 20 }
const name = getProperty(user, 'name') // string
const age = getProperty(user, 'age') // number
// ✅ 约束泛型必须继承特定接口
interface HasId {
id: string | number
}
function findById<T extends HasId>(list: T[], id: string | number): T | undefined {
return list.find(item => item.id === id)
}
// ✅ 多个泛型参数
function merge<T extends object, U extends object>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 }
}4. 联合类型和交叉类型
// ✅ 联合类型 - 多选一
type LoadingState = 'idle' | 'loading' | 'success' | 'error'
type FormMode = 'add' | 'edit' | 'view'
type ButtonType = 'primary' | 'success' | 'warning' | 'danger' | 'info'
// ✅ 交叉类型 - 合并多个类型
type UserWithPermissions = UserVo & {
permissions: string[]
roles: string[]
}
// ✅ 条件类型
type NonNullable<T> = T extends null | undefined ? never : T
type ExtractStrings<T> = T extends string ? T : never
// ✅ 映射类型
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
type Partial<T> = {
[P in keyof T]?: T[P]
}5. 类型断言
谨慎使用类型断言,优先使用类型守卫。
// ✅ 合理使用 as 断言
const user = {} as UserVo
const element = document.querySelector('.btn') as HTMLButtonElement
// ✅ 使用 ! 非空断言 (确定不为 null)
const name = user.name!
const element = document.querySelector('.btn')!
// ✅ 使用类型守卫代替断言
if (isUserVo(data)) {
// TypeScript 自动推导 data 为 UserVo
console.log(data.userName)
}
// ❌ 避免: 双重断言 (危险)
const data = user as any as AdVo
// ❌ 避免: 不必要的断言
const count: number = ref(0) as Ref<number>6. 枚举和常量
// ✅ 使用 const enum (编译时内联)
const enum UserStatus {
NORMAL = '0',
DISABLED = '1'
}
// ✅ 使用 as const 创建字面量类型
const USER_STATUS = {
NORMAL: '0',
DISABLED: '1'
} as const
type UserStatusValue = typeof USER_STATUS[keyof typeof USER_STATUS]
// ✅ 使用联合类型代替枚举
type UserStatus = '0' | '1'
// 使用
const status: UserStatus = '0'7. 类型推导优化
充分利用 TypeScript 的类型推导能力。
// ✅ 利用类型推导
const user = {
name: '张三',
age: 20,
email: 'zhangsan@example.com'
} // 自动推导为 { name: string; age: number; email: string }
// ✅ 函数返回类型推导
function getUser() {
return {
name: '张三',
age: 20
}
} // 返回类型自动推导为 { name: string; age: number }
// ✅ 数组类型推导
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
] // Array<{ id: number; name: string }>
// ✅ 条件推导
const value = condition ? 'yes' : 'no' // 'yes' | 'no'8. 严格类型检查
启用 TypeScript 严格模式,提高代码质量。
// tsconfig.json
{
"compilerOptions": {
"strict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
}
}9. 类型文档化
为类型添加详细的 JSDoc 注释。
/**
* 用户信息接口
* @description 用户的详细信息,包含基本信息和扩展信息
*/
interface UserVo {
/**
* 用户ID
* @example 1
*/
id: number
/**
* 用户名
* @example 'admin'
*/
userName: string
/**
* 邮箱地址
* @example 'admin@example.com'
*/
email: string
/**
* 用户状态
* @description 0-正常 1-停用
* @default '0'
*/
status: '0' | '1'
}10. 避免常见陷阱
// ❌ 避免: 使用 any
const data: any = {}
// ✅ 正确: 使用 unknown
const data: unknown = {}
if (typeof data === 'object' && data !== null) {
// 类型守卫后安全使用
}
// ❌ 避免: 过度使用可选链
const name = user?.profile?.name?.firstName?.value
// ✅ 正确: 合理使用可选链
const name = user?.profile?.name ?? 'Unknown'
// ❌ 避免: 直接解构 Props
const { user, loading } = props
// ✅ 正确: 使用 toRef
const user = toRef(props, 'user')
const loading = toRef(props, 'loading')类型检查工具
1. VSCode 配置
// .vscode/settings.json
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}2. ESLint TypeScript 规则
// .eslintrc.js
module.exports = {
extends: [
'@vue/eslint-config-typescript'
],
rules: {
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'warn'
}
}3. 类型检查命令
# 类型检查
npm run type-check
# 类型检查(监听模式)
npm run type-check:watch
# 构建时类型检查
npm run build总结
RuoYi-Plus-UniApp 的类型系统通过全局类型声明、模块扩展、严格类型检查等方式,为项目提供了完整的类型安全保障。开发时应遵循类型使用规范和最佳实践,充分利用 TypeScript 的类型推导和类型守卫能力,避免使用 any 等不安全的类型,确保代码质量和开发体验。
