在 Vue 3 中,当组件接收的 props 可能是原始对象或 JSON 字符串时,可通过 toRefs + computed 组合实现自动、非侵入式的类型标准化,无需修改父组件、不破坏响应性,且规避直接赋值 props 的 ESLint 报错。
在 vue 3 中,当组件接收的 props 可能是原始对象或 json 字符串时,可通过 `torefs` + `computed` 组合实现自动、非侵入式的类型标准化,无需修改父组件、不破坏响应性,且规避直接赋值 props 的 eslint 报错。
在 Vue 3 的组合式 API 中,defineProps 返回的是只读响应式对象,
不可直接修改其属性
(如 props.data = parsedData),否则会触发运行时警告并被 ESLint(如 vue/no-setup-props-destructure)拦截。而 default 函数仅在 prop 未传值时生效,无法处理已传入但格式不一致(如 data: '{"id":1}')的场景。
此时,推荐采用「封装式转换」策略:利用 toRefs 将 props 解构为响应式引用,再通过 computed 对每个 prop 值做惰性解析——既保持响应性,又实现类型归一化,且完全不污染原始 props。
以下是一个生产就绪的工具函数:
在组件中使用:
立即学习
“
前端免费学习笔记(深入)
”;
✅
优势说明
:
零副作用
:不修改原始 props,符合 Vue 响应式设计原则;
按需解析
:computed 惰性执行,仅在模板或逻辑中首次访问时解析,避免初始化开销;
错误防护
:内置 try/catch,JSON 解析失败时回退至原始字符串并发出警告,保障组件健壮性;
类型精准
:TypeScript 泛型推导确保返回对象各字段类型剔除 string,提升开发体验。
⚠️
注意事项
:
若 props 中存在 number | string 等需区分语义的联合类型(如 id: number | string),该函数
不会误解析数字字符串
(因 typeof "123" === 'string',仍会尝试 JSON.parse("123") → 123),若需保留原始字符串形态,请在类型定义中明确排除,或改用自定义解析逻辑;
避免在 unjsonProps 内部执行高开销操作(如大型嵌套对象深克隆),因其会在每次 computed 计算时重复执行;
该方案适用于「解析后需持续响应更新」的场景;若确定数据仅需一次性处理且无需响应性,可改用 onBeforeMount + ref 缓存,但会失去响应联动能力。
综上,unjsonProps 是 Vue 3 下处理混合类型 props 的轻量、安全、可复用的标准解法。
// composables/unjsonProps.ts
import { computed, toRefs, Ref } from 'vue'
export function unjsonProps>(props: T) {
const refs = toRefs(props)
return Object.fromEntries(
Object.entries(refs).map(([key, ref]) => [
key,
computed(() => {
const value = ref.value
if (typeof value === 'string') {
try {
return JSON.parse(value)
} catch (e) {
console.warn(`[unjsonProps] Failed to parse prop "${key}" as JSON:`, value, e)
return value // fallback to original string on parse error
}
}
return value
})
])
) as { [K in keyof T]: Exclude }
}
ID: {{ normalized.id }}
Data: {{ normalized.data?.name }}
Theme: {{ normalized.config?.theme }}
