TypeScript:如何优雅的调用通过 $refs 获取的子组件实例的方法?
最近在使用 Vue 结合 TypeScript 的过程中,遇到了个问题,以至于困扰了我一段时间:通过 this.$refs.child
获取到 Vue 的子组件的实例后,访问子组件的实例方法会提示该方法不存在。
1 | import { Vue, Component, Ref } from 'vue-property-decorator' |
好吧,大家很容易发现这个问题是 shims-vue.d.ts
这个声明文件的锅,他会使所有 *.vue
文件导出为 Vue
类型。
该文件的内容为:
1 | declare module '*.vue' { |
所以,我想了几个办法可以来绕过这个问题:
使用
// @ts-ignore
,在 VSCode 中,可以保留正常的定义跳转功能1
2
3
4
5
6
7
8
9
export default class ParentComponent extends Vue {
() readonly dialog!: DialogComponent;
public show() {
// @ts-ignore
this.dialog.show(); // no error
}
}将其设置为
any
类型,不过会破坏定义跳转1
2
3
4
5
6
7
8
export default class ParentComponent extends Vue {
any; () readonly dialog!:
public show() {
this.dialog.show(); // no error
}
}为组件类创建一个接口类型,并将
Ref
设置为该接口类型,这样也可以保留正常的定义跳转功能1
2
3
4// components/types/index.ts
export interface DialogComponentInterface {
show: () => number;
}1
2
3
4
5
6
7// Child component
export default class DialogComponent extends Vue implements DialogComponentInterface {
public show() {
return 1;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13import DialogComponent from '@/components/comment-form.vue';
import { DialogComponentInterface } from '@/components/types';
({
components: { DialogComponent },
})
export default class ParentComponent extends Vue {
// 可以保留跳转定义功能 () readonly dialog!: DialogComponent & DialogComponentInterface;
public show() {
this.dialog.show(); // no error
}
}合并类型。与方案 3 相比,它的代码更少,但是它还是会破坏定义跳转
1
2
3
4
5
6
7
8
export default class ParentComponent extends Vue {
() => number }; () readonly dialog!: DialogComponent & { show:
public show() {
this.dialog.show(); // no error
}
}
最终我选择了方案 3 并用来解决该问题。因为这是由于 shims-vue.d.ts
的声明引起的问题,目前也没有想到其他比较好的解决方法。过段时间准备把项目升级到 Vue3.0,看看能不能从根本上解决这个问题。