- vue3 ts setup写法,支持全局变量提示。
vue3 ts版本通过app.config.globalProperties挂载全局变量,一些插件也会在此安装全局可用的变量。参考官文:https://cn.vuejs.org/api/application.html#app-config-globalpr...,但是挂载的变量没有类型定义,被当作了any类型,无法通过ctrl查看变量下的属性和方法。
下面是在main.ts里挂载全局变量,鼠标放到变量上发现是any类型:
在component里使用挂载的变量,无法识别挂载的变量类型:
全局挂载的变量无法识别类型,因此无法提供代码提示, 也不利于代码重构,错误检查等。需要给全局变量建立类型关联,下面是vue的解决方式:vue通过利用ts的模块扩展特性,给挂载的变量指定类型,参考官文:https://cn.vuejs.org/guide/typescript/options-api.html#augmen...
globalProperties是ComponentCustomProperties类型,原生是没有我们挂载上去的变量的,因此用下面的方式扩展这个类型定义:
在src下写一个d.ts的类型定义文件,按照官网的文档扩展类型定义,至此$bus $api被扩展到了ComponentCustomProperties类型里,proxy就是ComponentCustomProperties类型,有了关联关系,代码提示就有了。
一些vue专用的插件或者库,一般会在自己的d.ts里定义vue的扩展类型,如pinia.d.ts定义了支持vue2及vue3的扩展类型:
- 下面处理下setup模式下proxy提示问题:
setup模式下需要通过proxy访问全局变量,在ts里引用proxy需要解决代码提示问题,这样写在js中没有问题:
在ts里会警告proxy不存在,这是ts的联合类型导致的,proxy是ComponentInternalInstance下的属性,但getCurrentInstance返回的可能是null。
下面是几种解决这个提示问题的方案,4,5应该是比较好的选择。
- 最简单的就是忽略这个警告,也可以强转为any类型消除警告,但这样就无法利用ts的提示能力了。
- 要利用ts的类型提示能力,需要强转为类型ComponentInternalInstance:
const { proxy } = getCurrentInstance() as ComponentInternalInstance ;
import的警告消除了,不过代码里使用的地方还有警告:
proxy可能存在也可能不存在,因此需要用可选链操作符改下代码:
至此用上了ts的类型提示,消除了所有警告。不过每个proxy后需要跟个可选链操作符,这让人感觉不爽,下面的方法可以解决这种问题:
- 引入proxy时选择下面两种写法之一即可,都是比较推荐的写法:
import { onMounted, onUnmounted, ref, reactive, getCurrentInstance, ComponentInternalInstance, ComponentPublicInstance } from 'vue';
// 写法一:使用可选链操作符 + 强转类型
const proxy = getCurrentInstance()?.proxy as ComponentPublicInstance;或者:
// 写法二:2次强转类型
const proxy = (getCurrentInstance() as ComponentInternalInstance).proxy as ComponentPublicInstance;
至此完全支持了ts,有了代码提示,类型检查。ts的类型检查,联合类型确实比较麻烦,需要耗费不少精力处理类型问题。
- 提取proxy到独立文件中
上面的写法也有一些缺陷,为了强转,需要在每个用到全局变量的component里引入这两个类:ComponentInternalInstance, ComponentPublicInstance。将引入抽离到独立的文件是个好主意,写一个useProxy.ts文件:
import { getCurrentInstance, ComponentInternalInstance, ComponentPublicInstance } from 'vue';
export default () => (getCurrentInstance() as ComponentInternalInstance).proxy as ComponentPublicInstance;
使用时这样引入即可:
import useProxy from '@/hooks/useProxy';
const proxy = useProxy();
- 使用全局对象
也创建一个独立的文件:useGlobalProperties.ts
import { getCurrentInstance, ComponentInternalInstance } from 'vue';
export default () => (getCurrentInstance() as ComponentInternalInstance).appContext.config.globalProperties;
使用时这样引入:
import useGlobalProperties from '@/hooks/useGlobalProperties';
const proxy = useGlobalProperties();
// 获取设备
proxy.$api.GetDeviceTree('1', '2')
globalProperties是实打实的挂载全局变量的对象,就是main里用到的那个,因此更容易理解。
proxy则是经过封装的Proxy对象,使用起来不够直观。