1、数组写法
const props = defineProps(["applyBasicInfo", "operateCommandType"]);
这是一个非常基础的 Vue props 声明方式,适用于简单场景。以下是详细解释:
📜 代码含义
javascript
const props = defineProps(["applyBasicInfo", "operateCommandType"]);
-
作用:声明组件接收两个 props(属性)
-
特点:仅指定 prop 名称,不进行任何类型校验
-
等价于:
javascript
defineProps({applyBasicInfo: null, // 无类型检查operateCommandType: null // 无类型检查 })
🔍 关键特性分析
1. 极简声明
-
只声明 props 的名称(字符串数组)
-
不校验类型
-
没有默认值
-
不强制 required
2. 适用场景
-
快速原型开发
-
不需要类型检查的简单组件
-
临时过渡代码
3. 实际效果
vue
<!-- 父组件 --> <ChildComponent :applyBasicInfo="任何类型的数据" <!-- 可以是对象、字符串、数字等 -->operateCommandType="任何内容" <!-- 可以是任意类型 --> /><!-- 子组件 --> <script setup> // 使用时需要自行确保类型正确 console.log(props.applyBasicInfo) // 可能是任意类型 </script>
🆚 与其他声明方式的对比
特性 | 数组写法 | 对象写法(完整) | TypeScript 类型写法 |
---|---|---|---|
类型校验 | ❌ 无 | ✅ Vue 运行时校验 | ✅ 编译时校验 |
默认值 | ❌ 不能设置 | ✅ 通过 default 设置 | ✅ 通过 withDefaults 设置 |
必需性控制 | ❌ 默认都是可选 | ✅ 通过 required 控制 | ✅ 通过 ? 符号控制 |
类型提示 | ❌ 无 | 🟡 基础类型提示 | ✅ 完整类型提示 |
代码安全性 | 🔴 低(可能运行时出错) | 🟡 中(有基础校验) | 🟢 高(编译时拦截错误) |
⚠️ 潜在风险示例
vue
<!-- 父组件传递错误类型 --> <ChildComponent :applyBasicInfo="123" <!-- 传递数字 -->operateCommandType <!-- 未传递 --> /><!-- 子组件使用时 --> <script setup> // 可能引发运行时错误 props.applyBasicInfo.name // 报错:数字没有 name 属性 props.operateCommandType // 拼写错误也不会警告(正确是 operateCommandType) </script>
💡 为什么要用这种写法?
-
历史兼容:Vue 2 的 props 数组写法在 Vue 3 中仍然可用
-
快速开发:节省写类型校验的时间
-
简单场景:当 props 类型不重要或可以确定时
🛠️ 如何改进?
基础改进(添加类型校验):
javascript
const props = defineProps({applyBasicInfo: {type: Object,required: true},operateCommandType: {type: String,default: "view"} });
高级改进(TypeScript):
typescript
interface ApplyBasicInfo {id: number;name: string; }const props = defineProps<{applyBasicInfo: ApplyBasicInfo;operateCommandType?: string; }>();
📌 最佳实践建议
-
仅用于临时代码:正式项目建议使用完整声明
-
配合 JSDoc 使用(如果不用 TypeScript):
javascript
/*** @typedef {Object} ApplyBasicInfo* @property {number} id* @property {string} name*/const props = defineProps(["applyBasicInfo", "operateCommandType"]);
-
渐进式增强:后续逐步替换为完整声明
这种写法就像骑自行车不戴头盔——简单快捷,但不够安全。建议新手仅在快速验证想法时使用,正式开发中尽量使用更完善的 props 声明方式。
2、 对象写法(纯 JavaScript 项目的写法,运行时 props 声明)
const props = defineProps({applyBasicInfo: {type: Object, // 要求必须是 Object 类型required: true // 表示父组件必须传递这个prop,不能与 default 同时使用},operateCommandType: {type: String, // 要求必须是 String 类型default: "info-view" // 表示当父组件没有传递时使用默认值,不能与 required 同时使用}
});
数组简写 vs 对象写法
javascript
复制
// 简写方式(不推荐) defineProps(['applyBasicInfo', 'operateCommandType'])// vs // 当前对象写法(推荐) defineProps({applyBasicInfo: { type: Object, required: true },operateCommandType: { type: String, default: "info-view" } })
特性 | 数组写法 | 对象写法 |
---|---|---|
类型检查 | ❌ 无 | ✅ 基础类型检查 |
默认值 | ❌ 不可设置 | ✅ 可设置 |
必填控制 | ❌ 默认全部可选 | ✅ 精确控制 |
代码安全性 | 🔴 低 | 🟡 中等 |
这段代码使用 Vue 的 defineProps
方法声明组件需要接收的两个 props(组件参数),并设置了参数的基本验证规则。
3、 TypeScript 的类型声明写法
3.1、使用标准的PropType进行对象类型定义
import type { PropType } from "vue";
import type { ApplyBasicInfo } from "@/interface";const props = defineProps({applyBasicInfo: {type: Object as PropType<ApplyBasicInfo>, // 使用标准的PropType进行对象类型定义required: true // 表示父组件必须传递这个prop,不能与 default 同时使用},operateCommandType: {type: String,default: "info-view" // 表示当父组件没有传递时使用默认值,不能与 required 同时使用}
});
🔍 关键概念拆解
1. 类型导入部分
typescript
import type { PropType } from "vue"; import type { ApplyBasicInfo } from "@/interface";
-
PropType
:Vue 提供的类型工具,用于在运行时声明中指定复杂类型 -
ApplyBasicInfo
:自定义的业务数据类型(通常定义在src/interface.ts
等位置) -
import type
:TypeScript 语法,表示只导入类型信息,不导入实际代码
2. 核心 props 声明
typescript
applyBasicInfo: {type: Object as PropType<ApplyBasicInfo>, // 类型断言required: true }
-
Object
:Vue 的运行时类型校验(基础对象类型) -
as PropType<ApplyBasicInfo>
:类型断言,告诉 TypeScript 这个对象的具体结构 -
双重效果:
-
运行时:Vue 检查传入的是否为对象
-
开发时:TypeScript 检查对象是否符合
ApplyBasicInfo
的结构
-
3. 对比普通对象声明
typescript
// 普通写法(只有 Vue 校验) applyBasicInfo: {type: Object, // 只知道是个对象,不清楚具体结构required: true }// 当前写法(Vue校验 + TS类型) applyBasicInfo: {type: Object as PropType<ApplyBasicInfo>, // 明确对象结构required: true }
🛠️ 工作原理图示
mermaid
graph TDA[父组件传递 props] --> B{Vue 运行时校验}B -->|通过| C[组件内使用]B -->|不通过| D[控制台警告]C --> E[TypeScript 类型检查]E -->|类型正确| F[正常开发]E -->|类型错误| G[IDE 提示错误]
💡 为什么要这样写?
优势对比表
特性 | 普通 Object 类型 | 当前写法 |
---|---|---|
代码提示 | 只知道是对象,无具体属性提示 | ✅ 显示 ApplyBasicInfo 的所有属性 |
重构安全性 | 修改属性时不会报错 | ✅ 修改接口定义会引发相关代码报错 |
参数校验 | 只校验是否是对象 | ✅ 运行时对象校验 + 类型结构校验 |
协作效率 | 需要查文档看数据结构 | ✅ 直接通过提示查看数据结构 |
示例类型定义
typescript
// 假设在 @/interface 中 interface ApplyBasicInfo {id: number; // 申请IDapplicant: string; // 申请人姓名status: 'pending' | 'approved'; // 申请状态createTime: Date; // 创建时间 }
🚀 在组件中的实际使用
智能提示示例
typescript
// 正确使用(有提示) props.applyBasicInfo.id // 提示 number 类型 props.applyBasicInfo.applicant // 提示 string 类型// 错误使用(立即报错) props.applyBasicInfo.APPlicant // ❌ 拼写错误提示 props.applyBasicInfo.status = 'rejected' // ❌ 类型不匹配
对应模板使用
vue
<template><!-- 显示申请人信息 --><div>{{ props.applyBasicInfo.applicant }}</div><!-- 根据操作类型显示不同内容 --><div v-if="operateCommandType === 'info-view'">查看模式</div> </template>
⚠️ 常见错误及解决方案
错误1:未定义接口
typescript
// 错误提示:Cannot find name 'ApplyBasicInfo' // 解决方案:确保类型文件正确定义并导出 // 在 @/interface.ts 中: export interface ApplyBasicInfo { ... }
错误2:错误类型传递
vue
<!-- 父组件传递错误数据结构 --> <MyComponent :apply-basic-info="{ id: '100' }" /> <!-- 错误:id 应该是 number -->
错误3:缺少必要属性
typescript
// 组件内使用时 const submit = () => {console.log(props.applyBasicInfo.createTime) // 如果接口中有该属性 } // 当父组件传递的对象缺少 createTime 时,TS 会报错
🆚 不同技术栈的写法对比
场景 | JavaScript 写法 | TypeScript 基础写法 | 当前进阶写法 |
---|---|---|---|
props 类型 | type: Object | type: Object | Object as PropType<T> |
代码提示 | 无 | 显示 Object 类型 | 显示具体接口属性 |
类型安全 | 低 | 中 | 高 |
维护成本 | 高(需口头沟通数据结构) | 中(需查看接口定义) | 低(直接提示数据结构) |
📌 最佳实践建议
-
接口定义规范:
-
在
src/types
或src/interface
目录统一管理类型 -
为每个接口添加文档注释
typescript
interface ApplyBasicInfo {/*** 申请的唯一标识* @example 123456*/id: number; }
-
-
props 校验增强:
typescript
applyBasicInfo: {type: Object as PropType<ApplyBasicInfo>,required: true,validator: (value: ApplyBasicInfo) => {return !!value.id // 添加自定义校验逻辑} }
-
默认值处理技巧:
typescript
// 对于复杂对象,建议提供默认值函数 applyBasicInfo: {type: Object as PropType<ApplyBasicInfo>,default: () => ({ id: 0, applicant: '', status: 'pending' }) }
这种写法是 Vue 3 项目中平衡类型安全和开发效率的典型实践,既能享受 TypeScript 的类型提示优势,又保留了 Vue 原有的 props 校验机制,特别适合中大型项目维护使用。
3.2、混合写法(结合了 Vue 的运行时 props 校验和 TypeScript 类型提示的混合写法)
import type { ApplyBasicInfo } from "@/interface";const props = defineProps({applyBasicInfo: {type: Object as () => ApplyBasicInfo, // 使用箭头函数返回类型required: true // 表示父组件必须传递这个prop,不能与 default 同时使用},operateCommandType: {type: String,default: "info-view" // 表示当父组件没有传递时使用默认值,不能与 required 同时使用}
});
这是一个结合了 Vue 的运行时 props 校验和 TypeScript 类型提示的混合写法代码,特别适用于 Vue 3 + TypeScript 项目。以下是逐层解析:
📜 代码结构解析
typescript
import type { ApplyBasicInfo } from "@/interface"; // 导入类型const props = defineProps({applyBasicInfo: {type: Object as () => ApplyBasicInfo, // 核心类型声明required: true},operateCommandType: {type: String,default: "info-view"} });
🔍 关键部分详解
1. 类型导入
typescript
import type { ApplyBasicInfo } from "@/interface";
-
作用:导入自定义类型(通常定义在
src/interface.ts
或类型声明文件中) -
示例类型定义:
typescript
// 假设在 @/interface 中 interface ApplyBasicInfo {id: number;name: string;status: 'pending' | 'approved';createTime: Date; }
2. defineProps 函数
typescript
const props = defineProps({...});
-
Vue 3 特有语法:用于声明组件接收的 props
-
返回响应式对象:包含所有已声明的 props
3. applyBasicInfo 属性
typescript
{type: Object as () => ApplyBasicInfo,required: true }
-
运行时类型:
Object
表示接受对象类型(Vue 的运行时校验) -
类型断言:
as () => ApplyBasicInfo
为 TypeScript 提供类型提示 -
实际效果:
typescript
// 使用时可以获得类型提示 props.applyBasicInfo.id // 提示 number 类型 props.applyBasicInfo.name // 提示 string 类型
4. operateCommandType 属性
typescript
{type: String,default: "info-view" }
-
标准 Vue 校验:接受字符串类型
-
默认值:当父组件未传递时默认为 "info-view"
🌟 代码特点
特性 | 说明 |
---|---|
双重校验 | Vue 运行时类型检查 + TypeScript 静态类型提示 |
明确契约 | 通过 ApplyBasicInfo 接口明确定义数据结构 |
渐进式类型 | 不需要完全迁移到 TypeScript 也能获得部分类型优势 |
代码可维护性 | 接口修改只需改动一处定义 |
🆚 不同写法的对比
这种写法 | 纯 TypeScript 写法 | 纯 JavaScript 写法 | |
---|---|---|---|
类型提示 | ✅ 完整类型提示 | ✅ 完整类型提示 | ❌ 无 |
运行时校验 | ✅ Vue 会校验 Object 类型 | ❌ 需额外配置 | ✅ 标准校验 |
默认值支持 | ✅ 直接通过 default 设置 | ❌ 需要使用 withDefaults | ✅ 原生支持 |
代码复杂度 | 🟡 中等 | 🟢 简洁(类型优先) | 🔴 高(需自行维护类型约束) |
💡 为什么这样写?
-
平衡开发体验:
-
获得 TypeScript 的智能提示
-
保留 Vue 的运行时校验安全网
-
-
渐进增强:
-
适合逐步将 JavaScript 项目迁移到 TypeScript
-
不需要一次性重写所有类型
-
-
明确数据契约:
typescript
// 父组件使用时 <MyComponent :apply-basic-info="{id: 123, // ✅ 必须 numbername: '张三', // ✅ 必须 stringstatus: 'pending', // ✅ 必须是枚举值createTime: new Date() // ✅ 必须 Date}" />
⚠️ 常见错误示例
typescript
// 错误1:缺少必填字段 props.applyBasicInfo.missingProp // ❌ TS 报错:属性不存在// 错误2:类型不匹配 props.applyBasicInfo.id = "100" // ❌ TS 报错:不能将 string 赋给 number// 错误3:错误的值类型 <MyComponent :apply-basic-info="'字符串'" /> // ❌ Vue 控制台警告:期望 Object,得到 String
🛠️ 在组件中的使用
vue
<script setup> // 获得智能提示 const submit = () => {console.log(props.applyBasicInfo.id) // 正确:number 类型console.log(props.operateCommandType.toUpperCase()) // 正确:string 方法 }// 类型安全操作 const statusLabel = computed(() => {switch(props.applyBasicInfo.status) {case 'pending': return '审批中';case 'approved': return '已通过';// case 'rejected' 会触发 TS 错误(如果接口中未定义)} }) </script>
📌 最佳实践建议
-
保持接口同步:当
ApplyBasicInfo
类型修改时,需要同步更新所有使用它的组件 -
默认值处理:对于复杂对象 prop,建议:
typescript
// 使用解构默认值 const { applyBasicInfo = DEFAULT_INFO } = toRefs(props)
-
文档注释:在接口定义处添加详细注释
typescript
interface ApplyBasicInfo {/** 申请ID,唯一标识 */id: number;/** 申请人姓名 */name: string;// ... }
这种写法特别适合需要逐步引入 TypeScript 的 Vue 项目,既能享受类型系统的优势,又不会完全颠覆原有的开发模式。
3.3、与3.1等效的TypeScript 的类型声明写法
import { toRefs } from "vue";
import type { ApplyBasicInfo } from "@/interface";const props = defineProps<{applyBasicInfo: ApplyBasicInfo;operateCommandType: string;
}>();// 需要单独定义默认值
const { operateCommandType = "info-view" } = toRefs(props);
这段代码是 Vue 3 组合式 API 中使用 TypeScript 的类型声明写法,主要用于定义组件的 props。让我们分步详细解释:
-
defineProps 的作用:
-
这是 Vue 3 的组合式 API 函数,用于声明组件接收的 props
-
类似于选项式 API 中的
props
选项,但更符合组合式 API 的编程风格
-
-
泛型参数
<...>
:-
这是 TypeScript 的泛型语法,用于为 defineProps 提供类型注解
-
泛型参数中定义了一个对象类型,描述了这个组件接收的所有 props 及其类型
-
-
props 具体定义:
typescript
{applyBasicInfo: ApplyBasicInfo;operateCommandType: string; }
-
声明了组件需要接收两个 props:
a) applyBasicInfo:
-
类型为
ApplyBasicInfo
(这应该是一个自定义的 TypeScript 类型/接口) -
可能是一个包含申请基本信息的对象,比如:
typescript
interface ApplyBasicInfo {id: number;applicantName: string;applyDate: Date;// ...其他字段 }
b) operateCommandType:
-
类型为
string
-
可能用于表示操作命令类型,比如:"create"、"edit"、"view" 等字符串枚举值
-
-
最终结果:
-
定义了一个名为
props
的常量 -
该常量包含两个响应式属性:
javascript
{applyBasicInfo: { /* 具体数据 */ },operateCommandType: "edit" // 示例值 }
-
-
在组件中的使用:
vue
// 父组件使用 <ChildComponent :applyBasicInfo="myApplyInfo" operateCommandType="edit" />// 子组件内使用 console.log(props.applyBasicInfo.applicantName) console.log(props.operateCommandType)
-
类型检查:
-
如果父组件传递错误类型的 prop,TypeScript 会给出编译时错误
-
例如:传递数字类型的 operateCommandType 会报错
-
-
对比 JavaScript 版本:
如果是纯 JavaScript,等效写法可能是:javascript
const props = defineProps({applyBasicInfo: {type: Object,required: true},operateCommandType: {type: String,default: 'view'} })
注意事项:
-
需要确保
ApplyBasicInfo
类型已经在项目中定义(通常是在独立的类型声明文件中) -
这种写法需要 Vue 3.3+ 版本支持
-
如果不需要 TypeScript 类型检查,可以使用运行时声明方式
-
这种写法默认 props 都是 required 的,如果需要可选参数,应该使用
propName?: Type
的语法