VueJS 2 + TypeScript下computed无法识别data定义属性的类型报错问题
问题复现
如下组件代码:
<template lang="html"> <div> <p>{{ bar }}</p> </div> </template> <script lang="ts"> import Vue from 'vue'; export const FooBar = Vue.extend({ computed: { bar: function() { return this.foo; } }, data: function() { return { foo: 'bar', }; }, }); export default FooBar; </script>
触发TypeScript错误:
13:19 Property 'foo' does not exist on type 'CombinedVueInstance<Vue, unknown, unknown, unknown, Readonly<Record<never, any>>>'. 11 | computed: { 12 | bar: function() { > 13 | return this.foo; | ^ 14 | } 15 | }, 16 | data: function() { Version: typescript 4.1.6
错误原因
该报错是Vue 2 中Vue.extend的类型推导能力限制导致的:TypeScript 无法自动识别未按推导顺序声明的组件选项类型,当computed写在data之前时,TS 尚未完成对data返回值的类型推导,就会判定this上不存在foo属性。
可行解决方案(无需使用类式组件语法)
- 方案1:调整组件选项书写顺序
将data选项移到computed等其他选项之前,让TS优先推导data类型,即可自动完成后续类型识别,修改后代码如下:
<template lang="html"> <div> <p>{{ bar }}</p> </div> </template> <script lang="ts"> import Vue from 'vue'; export const FooBar = Vue.extend({ data: function() { return { foo: 'bar', }; }, computed: { bar: function() { return this.foo; } }, }); export default FooBar; </script>
- 方案2:显式声明泛型参数
如果需要保留原有选项顺序,可以手动给Vue.extend传入泛型参数,声明组件的各类选项类型,写法如下:
import Vue from 'vue'; // 声明data类型 interface ComponentData { foo: string } // 声明computed类型 interface ComponentComputed { bar: string } // 泛型参数顺序:Data、Methods、Computed、Props、基础Vue实例类型 export const FooBar = Vue.extend<ComponentData, unknown, ComponentComputed, unknown>({ computed: { bar: function() { return this.foo; } }, data: function() { return { foo: 'bar', }; }, }); export default FooBar;
- 方案3:使用
defineComponent
Vue 3 内置的defineComponentAPI 优化了Options API的类型推导能力,无需调整选项顺序即可自动识别所有属性。如果是Vue 2项目,可以安装vue-demi包适配使用defineComponent,Vue3项目直接使用即可:
import { defineComponent } from 'vue'; export const FooBar = defineComponent({ computed: { bar() { return this.foo; } }, data() { return { foo: 'bar', }; }, }); export default FooBar;
- 方案4:使用Composition API写法
Composition API天然对TypeScript支持友好,类型推导更直观,无需处理this的类型问题。Vue2项目可安装@vue/composition-api包使用,Vue3内置支持:
import { defineComponent, ref, computed } from 'vue'; export default defineComponent({ setup() { const foo = ref('bar'); const bar = computed(() => foo.value); return { foo, bar } } })
内容的提问来源于stack exchange,提问作者David Roussov
相关产品推荐
相关产品推荐

