Vue组件跨TS文件导入方法:TypeScript类型报错问题求助
把Vue组件的方法拆分到test.ts和test2.ts两个文件,合并后组件调用所有方法都能正常运行,但在test2.ts的handleClick3方法里调用test.ts的methods1时,VSCode会报类型错误,虽然代码实际执行没问题。
报错信息(翻译后)
类型“CreateComponentPublicInstance<{}, {}, {}, {}, { methods3(): void; handleClick3(term: any): void; methods23(): void; }, ComponentOptionsMixin, ComponentOptionsMixin, ... 11 more ..., {}>”上不存在属性“methods1”
原因
用defineComponent定义test2.ts时,TypeScript只会根据当前文件里的方法推断this的类型,完全不知道这个方法对象之后会和test.ts的方法合并到组件实例中,所以类型检查时认为this没有methods1方法,从而抛出错误。
解决办法
方法1:临时类型断言(快速解决)
在test2.ts调用methods1时,把this断言成any或者包含目标方法的类型,跳过类型检查:
// test2.ts handleClick3(term: any) { console.log('handleClick3') (this as any).methods1() }
如果想更严谨,可以先定义包含目标方法的接口再断言:
// test2.ts interface ExtendedMethods { methods1(): void } export default defineComponent({ methods: { handleClick3(term: any) { console.log('handleClick3') (this as ExtendedMethods).methods1() }, // 其他方法... } })
方法2:统一定义组件方法类型(更规范)
先在单独的类型文件(比如types.ts)里定义所有组件方法的类型:
// types.ts export interface ComponentMethods { methods1(): void methods2(): void methods3(): void handleClick(term: any): void handleClick3(term: any): void methods23(): void }
然后在test.ts和test2.ts里用这个接口约束this的类型:
// test.ts import { defineComponent } from "vue" import test2 from "./test2" import type { ComponentMethods } from "./types" export default defineComponent({ methods: { methods1(this: ComponentMethods): void { console.log('methods1') this.methods3() }, handleClick(this: ComponentMethods, term: any) { this.handleClick3() }, methods2(): void { console.log('methods2') }, ...test2.methods as ComponentMethods } })
// test2.ts import { defineComponent } from "vue" import type { ComponentMethods } from "./types" export default defineComponent({ methods: { methods3(): void { console.log('methods') }, handleClick3(this: ComponentMethods, term: any) { console.log('handleClick3') this.methods1() }, methods23(this: ComponentMethods): void { console.log('methods2') console.log(this.$data) } } })
方法3:不用defineComponent包裹拆分的方法(更简洁)
直接导出方法对象,让主组件的defineComponent统一推断类型:
// test.ts import test2 from "./test2" export default { methods: { methods1(): void { console.log('methods1') this.methods3() }, handleClick(term: any) { this.handleClick3() }, methods2(): void { console.log('methods2') }, ...test2.methods } }
// test2.ts export default { methods: { methods3(): void { console.log('methods') }, handleClick3(term: any) { console.log('handleClick3') this.methods1() }, methods23(): void { console.log('methods2') console.log(this.$data) } } }
这样主组件的defineComponent会合并所有方法,正确推断this的类型,test2.ts里的this也会被TypeScript正确识别为组件实例类型。
内容的提问来源于stack exchange,提问作者Nikolay Markov

