2
  1. vue3 ts setup写法,支持全局变量提示。

vue3 ts版本通过app.config.globalProperties挂载全局变量,一些插件也会在此安装全局可用的变量。参考官文:https://cn.vuejs.org/api/application.html#app-config-globalpr...,但是挂载的变量没有类型定义,被当作了any类型,无法通过ctrl查看变量下的属性和方法。

下面是在main.ts里挂载全局变量,鼠标放到变量上发现是any类型:
Image.png

在component里使用挂载的变量,无法识别挂载的变量类型:
Image.png

全局挂载的变量无法识别类型,因此无法提供代码提示, 也不利于代码重构,错误检查等。需要给全局变量建立类型关联,下面是vue的解决方式:vue通过利用ts的模块扩展特性,给挂载的变量指定类型,参考官文:https://cn.vuejs.org/guide/typescript/options-api.html#augmen...
globalProperties是ComponentCustomProperties类型,原生是没有我们挂载上去的变量的,因此用下面的方式扩展这个类型定义:
Image.png
在src下写一个d.ts的类型定义文件,按照官网的文档扩展类型定义,至此$bus $api被扩展到了ComponentCustomProperties类型里,proxy就是ComponentCustomProperties类型,有了关联关系,代码提示就有了。

一些vue专用的插件或者库,一般会在自己的d.ts里定义vue的扩展类型,如pinia.d.ts定义了支持vue2及vue3的扩展类型:
Image.png

  1. 下面处理下setup模式下proxy提示问题:

setup模式下需要通过proxy访问全局变量,在ts里引用proxy需要解决代码提示问题,这样写在js中没有问题:
Image.png
在ts里会警告proxy不存在,这是ts的联合类型导致的,proxy是ComponentInternalInstance下的属性,但getCurrentInstance返回的可能是null。
下面是几种解决这个提示问题的方案,4,5应该是比较好的选择。

  1. 最简单的就是忽略这个警告,也可以强转为any类型消除警告,但这样就无法利用ts的提示能力了。
  2. 要利用ts的类型提示能力,需要强转为类型ComponentInternalInstance:
const { proxy } = getCurrentInstance() as ComponentInternalInstance ;

import的警告消除了,不过代码里使用的地方还有警告:
Image.png
proxy可能存在也可能不存在,因此需要用可选链操作符改下代码:
Image.png
至此用上了ts的类型提示,消除了所有警告。不过每个proxy后需要跟个可选链操作符,这让人感觉不爽,下面的方法可以解决这种问题:

  1. 引入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;

Image.png
至此完全支持了ts,有了代码提示,类型检查。ts的类型检查,联合类型确实比较麻烦,需要耗费不少精力处理类型问题。

  1. 提取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();
  1. 使用全局对象

也创建一个独立的文件: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对象,使用起来不够直观。


cp1001
20 声望0 粉丝