在 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。
以下是一个生产就绪的工具函数:
// composables/unjsonProps.tsimport { computed, toRefs, Ref } from 'vue'export function unjsonProps<T extends Record<string, any>>(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<T[K], string> }}
在组件中使用:
<script setup lang="ts">import { unjsonProps } from '@/composables/unjsonProps'interface Props { data: Record<string, any> | string config: { theme: string } | string id: number | string // note: number/string stays unchanged}const props = defineProps<Props>()const normalized = unjsonProps(props)// ✅ 此时 normalized.data 和 normalized.config 均为解析后的对象(响应式)// ✅ normalized.id 保持原值(因非 string 类型,跳过解析)</script><template> <div> <p>ID: {{ normalized.id }}</p> <p>Data: {{ normalized.data?.name }}</p> <p>Theme: {{ normalized.config?.theme }}</p> </div></template>
优势说明:
注意事项:
综上,unjsonProps 是 Vue 3 下处理混合类型 props 的轻量、安全、可复用的标准解法。