Vite中的TS环境说明

vite天然引入ts。

Vite仅仅执行ts文件的转译工作,但是不会执行类型检查。因为已经默认你在IDEA/Vscode等编译器 或 构建过程里进行检查了,因此不会管了。

比如类型出错了,也依旧能够执行。

在main.ts改一下

  1. let count: number = 100
  2. count = 200
  3. console.log(count)//200
  4. count = 'hello'
  5. console.log(count)//'hello'

依旧运行了。

那么,构建过程里怎么验证的呢?

我们在package.json里其实已经配置过了

  1. "build": "vue-tsc --noEmit && vite build"

只有验证通过了,才会vite build

真的么?验证下,上面的错误我不修改,看看。

  1. npm run build
  2. src/main.ts:7:1 - error TS2322: Type 'string' is not assignable to type 'number'.
  3. 7 count = 'hello'
  4. ~~~~~
  5. Found 1 error in src/main.ts:7

果然报错了

在Vite里使用esbuild将TS转译成JS,比vue用的tsc快20-30倍,同时HMR更新反映到浏览器的时间小于50ms.

但是,因为esbuild只执行转译工作而不包含类型信息,所以不支持TS的特定功能例如常量枚举和隐式”type-only“导入。

所以我们必须在tsconfig.jsoncompilerOptions里设置"isolatedModules":true,这样TS才会警告我们哪些功能无法与esbuild这种独立编译模式一同工作。

(后来的版本已经默认设置了,无需进行这步了。)

客户端类型

Vite默认的类型定义是写给它的Node.js API的,不是给客户端代码环境的。如果要将其补充到一个Vite应用的客户端代码环境中,得添加一个d.ts声明文件:

  1. /// <reference types="vite/client" />

同时,也可以将vite/client添加到tsconfig中的compilerOption.types

  1. {
  2. "compilerOptions": {
  3. "types": ["vite/client"]
  4. }
  5. }

这将会提供以下类型定义补充:

  • 资源导入 (例如:导入一个 .svg 文件)
  • import.meta.env 上 Vite 注入的环境变量的类型定义
  • import.meta.hot 上的 HMR API 类型定义

主要就提供这三个,若没引入则没有。不过默认引入的d.ts声明文件的,叫vite-env.d.ts

在以前除了vite-env.d.ts, 还有shims-vue.d.ts,而最新版本已经将他直接加到vite-env.d.ts里了,也是ts的补充声明。 以下:

  1. declare module '*.vue' {
  2. import type { DefineComponent } from 'vue'
  3. const component: DefineComponent<{}, {}, any>
  4. export default component
  5. }

declare了一个 ‘.vue’, 以vue结尾的。在vue里加载了DefineComponent,定义了下又将其导出。其作用:*给Vue做类型声明,因为ts识别不了vue模块!

Vue3中的TS支持

其实vue3就是用ts编写的,对TS提供了一等公民的支持。所有的 Vue 官方库都自带了类型声明文件,开箱即用。

主要是项目配置。

项目配置

在单文件组件中的用法

要在单文件组件中使用 TypeScript,比如App.vue。需要在 <script> 标签上加上 lang="ts" 的 attribute。当 lang="ts" 存在时,所有的模板内表达式都将享受到更严格的类型检查。

简而言之,将lang="ts", 就将其下内容当做ts来使用了。最后编译构建时,转成js。不加lang="ts",就是js来对待。

  1. <script lang="ts">
  2. import { defineComponent } from 'vue'

也可以用于 <script setup>

  1. <script setup lang="ts">
  2. // 启用了 TypeScript
  3. import { ref } from 'vue'
  4. const count = ref(1)
  5. </script>

定义Vue组件

为了让 TypeScript 正确地推导出组件选项内的类型,需要用defineComonent全局方法来定义组件

  1. import { defineComponent } from 'vue'
  2. export default defineComponent({
  3. // 启用了类型推导
  4. props: {
  5. name: String,
  6. msg: { type: String, required: true }
  7. },
  8. data() {
  9. return {
  10. count: 1
  11. }
  12. },
  13. mounted() {
  14. this.name // 类型:string | undefined
  15. this.msg // 类型:string
  16. this.count // 类型:number
  17. }
  18. })

总结:

  1. lang=”ts”
  2. 要让TS正确推断Vue组件选项中的类型,需要使用defineComponent全局方法定义组件。

与组合式API一起使用

当使用 <script setup> 时,defineProps() 宏函数支持从它的参数中推导类型:

简而言之,在setup里,可以判断props组件里的类型,是字符串还是数字,都知道。

  1. <script setup lang="ts">
  2. const props = defineProps({
  3. foo: { type: String, required: true },
  4. bar: Number
  5. })
  6. props.foo // string
  7. props.bar // number | undefined
  8. </script>

PropType

若props的一个参数obj要定义一个有格式要求的对象怎么办?

并且没有使用