前言
在 Vue3 + TypeScript + pinia 项目中,使用 get() set() 定义计算属性时,出现 '不能将类型“WritableComputedRef<string>”分配给类型“string” ts(2322)' 或 "error TS2322: Type 'WritableComputedRef<string>' is not assignable to type 'string'" 错误
src/components/xxxx.vue(xx,xx): error TS2322: Type 'WritableComputedRef<string>' is not assignable to type 'string'.
错误复现
1. xxxx.vue 部分
<template>
<input v-model="textvalue" type="text" />
</template>
<script setup lang="ts">
import { computed } from 'vue'
// pinia
import { useHelloworldStore } from '../stores/helloworldStore'
const store = useHelloworldStore()
// 报错:不能将类型“WritableComputedRef<string>”分配给类型“string” ts(2322)
const textvalue: string = computed({
get() {
return store.textvalue
},
set(newValue: string) {
return store.changeTextvalue(newValue)
}
})
</script>
2. helloworldStore.ts 部分
import { defineStore } from 'pinia'
export const useHelloworldStore = defineStore('helloworldStore', {
state: () => {
return {
textvalue: '',
}
},
actions: {
changeTextvalue(newVal: string) {
setTimeout(() => {
this.textvalue = newVal
}, 300)
},
}
})
3. 错误原因
vue3 的 computed 函数返回的是一个 ref 类型的响应式对象,此处传入 string 类型的 get() 和 set() 后,computed 函数返回的是 WritableComputedRef<string> 类型的值,而非 string 类型
但本文在 textvalue 计算属性处声明的类型是 string,与返回类型 WritableComputedRef<string> 不符,所以会报错:不能将类型“WritableComputedRef<string>”分配给类型“string” ts(2322)
解决方案
方法一:删掉 textvalue 处的类型声明
利用 vue3 的 <script setup> 语法糖,vue3 会自动推断 textvalue 的类型为 WritableComputedRef<string> ,解决问题
// 验证通过
const textvalue = computed({
get() {
return store.textvalue
},
set(newValue: string) {
return store.changeTextvalue(newValue)
}
})
或使用 export default difineComponent({...}) 与 setup() 函数,同样会自动推断类型
方法二:声明 textvalue 为 WritableComputedRef<type> 类
从 vue 中引入 WritableComputedRef 类,将 textvalue 类型声明为 WritableComputedRef<type>,解决问题,适用于需要声明计算属性类型的场景
import { computed, type WritableComputedRef } from 'vue'
// 验证通过
const textvalue: WritableComputedRef<string> = computed({
get() {
return store.textvalue
},
set(newValue: string) {
return store.changeTextvalue(newValue)
}
})