一、问题汇总
在使用Visual Studio Code(VSCode)开发Vue3 + TypeScript项目时,会遇到各种波浪线错误(诊断信息),这些问题或错误通常由以下几人原因引起的:
1.1 常见问题
1、typeScript配置问题
- 确保tsconfig.json文件配置正确,这上配置文件告诉TypeSript编译如何处理项目中的.ts攻.tsx文件。
- 检查是否包含了正确的模块解析、编译顺选项等。
2、ESLint配置问题
- ESLint用于代码质量和风格检查,如果项目中使用了ESlint,则需要确保 .eslintrc.js 或 eslintrc.json 文件配置正确。
- 另外项目是Vue3 + TypeScript,则需要安装并配置相应的ESLint插件,如 @vue/eslint-config-typescipt、@typescript-eslnt/eslint-plugin 和@typescript-eslint/parser。一般使用Vue3脚手架安装,会在初始化选项中选择配置。
- 在ESlint配置中,确保parserOptions包含了{"parser": "@typescript-eslint/parser", "ecmaVersion": 2020, "sourceType": "module"} 等正确选择。
3、Vetur或Volar插件问题
- 对于Vue项目,VSCode社区提供了两个流行的插件:Vetur和Volar。Vetur早期更受欢迎,但Volar提供了对Vue3和TypeScript的更好支持。
- 如果使用了Vetur,遇到了TypeScript相关的问题,考虑切换到Volar。
- 确保您的插件是最新的,并且已正确安装,并处于开启状态。
4、项目依赖问题
- 确保项目依赖是最新的,特别是与Vue3和TypeScript相关的依赖包。
- 使用npm install 、 pnpm 或 yarn来安装所有依赖。这里推荐使用pnpm,其安装更快速。
5、第三方插件问题
- 确保您使用的第三方插件,是在Vue3 + TypeScript版本环境中完全适应的,有些第三方插件可能几年未更新,并不适合在Vue3+TS环境中运行,可能会导致各种未知的错误。
6、重启VSCode
- 有时候,可能项目较大或VSCode运行较久,导致一些未知问题,可以通过重启来解决。
1.2 解决问题
1、检查错误类型
- 仔细阅读VSCode中显示的错误或警告信息,这样可以帮助我们更快的定位到问题
- 可以将鼠标悬浮在波浪线上,获取更多信息,如“查看问题(Alt+8)”,或“快速修复”等。
2、搜索解决问题
- 利用互联网搜索具体的错误消息或错误代码,有可能会与其他开发者遇到雷同或相同的问题。
- 使用ChatGPT或文心一言等大模型,对问题进行分析和搜索解决方案。
二、declare关键字
在Vue3 + TypeScript的项目中,使用declare关键字来定义类型时,是为了告诉TypeScript编译器关于一些外部资源(如全局变量、模块扩展等)的类型信息。使用declare定义的类型通常不会直接影响组件内部或模块内部的具体实现,但可以影响TypeScript的类型检查过程。
当代码中某些变量或方法相关的波浪线消失了,这意味着通过定义的declare提供了足够的类型信息,让TypeScript能够理解并接受当前的用法。
2.1 创建类型目录
通常我们是在项目src目录下,创建一个types文件夹,用来创建和定义项目中需要的类型信息。通过在一个 .d.ts(声明文件)文件中声明相关类型来解决问题。
2.2 tsconfig.app.json配置
在创建types文件夹后,需要在tsconfig.app.json中配置下,告诉Typescript编译器类型查询位置,添加typeRoots配置项,代码如下:
{"extends": "@vue/tsconfig/tsconfig.dom.json","include": ["env.d.ts", "src/**/*", "src/**/*.vue"],"exclude": ["src/**/__tests__/*"],"compilerOptions": {"composite": true,"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo","typeRoots": ["./src/types"],"baseUrl": ".","paths": {"@/*": ["./src/*"]}}
}
2.3 注意事项
- 声明文件的位置:通常是将声明文件放置在项目src/types目录下,但这不是强制的。TypeScript会查找项目根目录和node-modules/@types下的声明文件。
- 全局作用域:使用declare声明的类型或变量是全局的,它们对项目中所有使用TypeScript的地方可见。
- 模块扩展:如果使用了Vuex或Vue Router,可能需要使用 declare module语法来扩展该模块的类型定义。
- 类型安全:虽然declare可以帮助我们绕开TypeScript的类型检查,但这不会为项目提供运行时安全。确保声明与运行时行为相匹配,以免导致运行时出错。
三、常见问题整理
在开始之前,我们先在scr/types目录下创建typings.d.ts文件,用于下面相关类型问题解决,提供可定义的文件。
3.1 opera属性不存在
如下图,在调用window对象的opera属性,显示其不存在属性“opera”。
在typings.d.ts文件中声明以下接口类型,代码如下:
// 解决平台判断中的opera不存在问题
declare interface Window {opera: any
}
3.2 window不存在问题
同样typings.d.ts中声明以下接口类型,在代码如下:
declare const window: Window | undefined
因window有可能为undefined,所以在使用前需要先判断是否存在,示例如下:
if(window) window.location.href = '跳转地址'
3.3 document不存在问题
声明类型,代码如下:
declare const document: Document
3.4 第三方插件
如上图,在使用qrcode生成二维码插件时,会出现波浪线,提示错误为:
无法找到模块“qrcode”的声明文件。
尝试使用 `npm i --save-dev @types/qrcode` (如果存在),或者添加一个包含 `declare module 'qrcode';` 的新声明(.d.ts)文件
这个提示信息给出了两种解决方案,我们使用第二种,在typings.d.ts中声明,代码如下:
// 将提示中第二种方案代码贴到typings.d.ts文件中即可
declare module 'qrcode'
3.4 类型声明
我们也可以在types目录中创建新的 *.d.ts文件,或者在typings.d.ts中声明全局类型。
当使用axios发送请求时,封装请求函数,并约束接口函数的入参和返回结果。这里还是在typings.d.ts中声明,代码如下:
// 请求响应类型接口(T为泛型,使用时指定)
declare interface ApiResponse<T> {msg: stringstatus: string | numberdata: T
}// 请求响应结果类型接口(T为泛型,使用时指定)
declare type ApiResult<T> = Promise<ApiResponse<T>>
然后在定义接口函数时,通过关联对应类型,来约束开发者传入约定的数据,并且得到可预见的结果。接口函数 代码如下:
// axios封装文件
import Request from '@/utils/request'// 定义通用接口函数,通过泛型N, M在运行时告诉程序,data和响应结果的数据结构类型
export const commonServiceApi = <N, M>(params: {methodName: string, data?: M}): ApiResult<N> => {const udata = { MethodName: params.methodName }Object.assign(udata, params['data'])return Request({url: APIServiceURL,method: "post",params: udata})
}
使用通用接口函数,例如获取菜单数据,代码如下:
// 声明菜单数据类型
type MenuType = {id: number,name: string,// 略...
}// 查询菜单数据
commonServiceApi<MenuType, unknown>({methodName: 'categoryList'}).then(res => {// do something...console.log(res)
})
当使用通用接口函数时,指定菜单响应数据类型为MenuType,则编译器就知道响应结果为MenuType了;因为这里没有入参数据,所以第二个泛型传的是unknown。
在Vue3 + TypeScript项目中,遇到波浪线问题,通常是类型错误、语法错误或配置问题,所以通过“一、问题汇总”中的方法,先仔细查看问题提示信息,再一一排查,基本解决绝大多数问题; 当经验积累起来后,很多问题在开发阶段就可以避免了。