You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue/Pinia中强制实现状态修改时的校验?

在Pinia中实现强制状态校验与类似Setter的约束

方案一:用ES6代理(Proxy)拦截所有状态修改

通过将初始状态包裹在Proxy中,拦截所有属性的赋值操作,强制触发校验逻辑。无论使用者是直接修改状态还是通过Action修改,都会被拦截,从根源上阻止非法值写入。

示例代码:

import { defineStore } from 'pinia'

function createValidatedState(initialState, validators) {
  return new Proxy(initialState, {
    set(target, prop, value) {
      // 执行对应属性的校验规则
      if (validators[prop]) {
        const isValid = validators[prop](value)
        if (!isValid) {
          throw new Error(`属性 ${prop} 不符合规则:传入值为 ${value}`)
        }
      }
      target[prop] = value
      return true
    }
  })
}

export const useCounterStore = defineStore('counter', {
  state: () => {
    const initialState = {
      count: 0
    }
    // 定义校验规则:count必须是数值类型
    const validators = {
      count: (value) => typeof value === 'number'
    }
    return createValidatedState(initialState, validators)
  },
  // 可选:提供规范的Action方法,Proxy已保证所有修改都走校验
  actions: {
    increment() {
      this.count++
    },
    setCount(value) {
      this.count = value
    }
  }
})

方案二:TypeScript类型约束+运行时校验(TS项目首选)

先通过TS类型定义约束状态属性的类型,在开发阶段给使用者明确的类型提示,再在Action中添加运行时校验,防止JS环境下的类型绕过。

示例代码:

import { defineStore } from 'pinia'

// 定义状态类型,约束属性类型
interface CounterState {
  count: number
}

export const useCounterStore = defineStore('counter', {
  state: (): CounterState => ({
    count: 0
  }),
  actions: {
    setCount(value: number) {
      // 运行时二次校验
      if (typeof value !== 'number') {
        throw new Error('count必须是数值类型')
      }
      this.count = value
    },
    increment() {
      this.count++
    }
  }
})

如果要彻底阻止直接修改,可以结合上面的Proxy方案,实现类型提示+强制校验的双重保障。

方案三:watch监听+状态回滚(兜底方案)

开启Vue严格模式,结合watch监听状态变化,发现非法值时抛出错误并恢复原状态。这种方式属于事后校验,适合不想引入Proxy的场景。

示例代码:

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    setCount(value) {
      if (typeof value !== 'number') {
        throw new Error('count必须是数值类型')
      }
      this.count = value
    }
  },
  created() {
    this.$watch('count', (newVal, oldVal) => {
      if (typeof newVal !== 'number') {
        console.error('count必须是数值类型')
        // 回滚到合法状态
        this.count = oldVal
        throw new Error('count必须是数值类型')
      }
    }, { deep: true })
  }
})

内容的提问来源于stack exchange,提问作者Oidipous_REXX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 23:30:07