外观
使用TypeScript配合Vue
类似于TypeScript的类型系统可以在构建时通过静态分析检测许多常见错误。这降低了生产环境中运行时错误的可能性,并使我们能够更自信地对大规模应用程序中的代码进行重构。TypeScript还通过IDE中的基于类型的自动完成来提高开发者的用户体验。
Vue是用TypeScript编写的,并提供了第一级的TypeScript支持。所有官方Vue包都包含了捆绑的类型声明,应该可以直接使用。
项目设置
create-vue
,官方的项目脚手架工具,提供了创建一个由Vite驱动、TypeScript就绪的Vue项目的选项。
概述
在基于Vite的设置中,开发服务器和打包器仅进行转译,不执行任何类型检查。这确保了即使在使用TypeScript的情况下,Vite开发服务器也能保持极快的速度。
在开发过程中,我们建议依赖一个好的IDE设置来即时反馈类型错误。
如果使用SFCs,请使用
vue-tsc
实用工具进行命令行类型检查和类型声明生成。vue-tsc
是TypeScript的自身命令行接口的包装器。它基本上与tsc
相同,除了它还支持Vue SFCs和TypeScript文件。您可以在Vite开发服务器并行运行的情况下以监控模式运行vue-tsc
,或者使用像vite-plugin-checker这样的Vite插件,它在一个单独的工作线程中运行检查。Vue CLI也提供了TypeScript支持,但不再推荐。请参阅下面的说明。
IDE支持
Visual Studio Code (VS Code)因其对TypeScript的出色支持而强烈推荐。
Vue - Official (之前称为Volar)是官方的VS Code扩展,它提供了Vue SFC内的TypeScript支持,以及许多其他优秀功能。
小贴士
Vue - Official扩展替换了Vetur,我们之前官方的Vue 2 VS Code扩展。如果您已经安装了Vetur,请确保在Vue 3项目中禁用它。
WebStorm也提供了对TypeScript和Vue的即开即用支持。其他JetBrains IDE也支持它们,要么是即开即用,要么是通过一个免费插件。截至2023.2版本,WebStorm和Vue插件都内置了对Vue语言服务器的支持。您可以在设置 > 语言和框架 > TypeScript > Vue下将Vue服务设置为使用Volar集成在所有TypeScript版本上。默认情况下,Volar将用于5.0及更高版本的TypeScript。
配置tsconfig.json
通过create-vue
构建的项目包括预配置的tsconfig.json
。基本配置被抽象在@vue/tsconfig
包中。在项目内部,我们使用项目引用来确保在不同环境中运行的代码具有正确的类型(例如,应用程序代码和测试代码应具有不同的全局变量)。
当手动配置tsconfig.json
时,一些值得注意的选项包括
compilerOptions.isolatedModules
被设置为true
,因为Vite使用esbuild进行TypeScript的转译,并受限于单个文件转译。compilerOptions.verbatimModuleSyntax
是isolatedModules
的超集,也是一个很好的选择——这是@vue/tsconfig
所使用的。如果您使用的是Options API,则需要将
compilerOptions.strict
设置为true
(或者至少启用compilerOptions.noImplicitThis
,它是strict
标志的一部分)以利用组件选项中this
的类型检查。否则,this
将被视为any
。如果您在构建工具中配置了解析器别名,例如在
create-vue
项目中默认配置的@/*
别名,您还需要通过compilerOptions.paths
为其配置TypeScript。如果您打算在Vue中使用TSX,请将
compilerOptions.jsx
设置为"preserve"
,并将compilerOptions.jsxImportSource
设置为"vue"
。
另请参阅
关于Vue CLI和ts-loader
的说明
在基于webpack的设置,例如Vue CLI中,通常将类型检查作为模块转换管道的一部分执行,例如使用ts-loader
。然而,这并不是一个完美的解决方案,因为类型系统需要了解整个模块图来执行类型检查。单个模块的转换步骤根本不适合这项任务。它导致了以下问题
ts-loader
只能检查转换后的代码。这与我们在IDE中看到的错误或来自vue-tsc
的错误不匹配,这些错误直接映射回源代码。类型检查可能很慢。当它与代码转换在同一个线程/进程中执行时,它会显著影响整个应用程序的构建速度。
我们已经在IDE中单独的进程中运行了类型检查,因此开发体验减速的成本并不是一个好的权衡。
如果您目前正在使用Vue 3 + TypeScript通过Vue CLI,我们强烈建议迁移到Vite。我们还在开发CLI选项以启用仅TS转译支持,这样您就可以切换到vue-tsc
进行类型检查。
一般使用说明
defineComponent()
为了让TypeScript正确推断组件选项中的类型,我们需要使用defineComponent()
来定义组件
ts
import { defineComponent } from 'vue'
export default defineComponent({
// type inference enabled
props: {
name: String,
msg: { type: String, required: true }
},
data() {
return {
count: 1
}
},
mounted() {
this.name // type: string | undefined
this.msg // type: string
this.count // type: number
}
})
defineComponent()
还支持在未使用 <script setup>
的情况下,通过 Composition API 推断传递给 setup()
的 props。
ts
import { defineComponent } from 'vue'
export default defineComponent({
// type inference enabled
props: {
message: String
},
setup(props) {
props.message // type: string | undefined
}
})
另请参阅
小贴士
defineComponent()
还为用纯 JavaScript 定义的组件启用了类型推断。
在单文件组件中的使用
要在 SFC 中使用 TypeScript,请向 <script>
标签添加 lang="ts"
属性。当存在 lang="ts"
时,所有模板表达式也享有更严格的类型检查。
vue
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
data() {
return {
count: 1
}
}
})
</script>
<template>
<!-- type checking and auto-completion enabled -->
{{ count.toFixed(2) }}
</template>
lang="ts"
也可以与 <script setup>
一起使用
vue
<script setup lang="ts">
// TypeScript enabled
import { ref } from 'vue'
const count = ref(1)
</script>
<template>
<!-- type checking and auto-completion enabled -->
{{ count.toFixed(2) }}
</template>
模板中的 TypeScript
当使用 <script lang="ts">
或 <script setup lang="ts">
时,<template>
也支持在绑定表达式中使用 TypeScript。这在需要在对模板表达式进行类型转换时非常有用。
以下是一个虚构的例子
vue
<script setup lang="ts">
let x: string | number = 1
</script>
<template>
<!-- error because x could be a string -->
{{ x.toFixed(2) }}
</template>
这可以通过内联类型转换来解决这个问题
vue
<script setup lang="ts">
let x: string | number = 1
</script>
<template>
{{ (x as number).toFixed(2) }}
</template>
小贴士
如果使用 Vue CLI 或基于 webpack 的设置,模板表达式中的 TypeScript 需要 vue-loader@^16.8.0
。
与 TSX 一起使用
Vue 还支持使用 JSX / TSX 创建组件。详细信息请参阅 渲染函数 & JSX 指南。
泛型组件
泛型组件支持两种情况
- 在 SFC 中:
<script setup>
带有generic
属性 - 渲染函数 / JSX 组件:
defineComponent()
的函数签名