各位观众老爷们,大家好!我是今天的主讲人,江湖人称“码农老王”。今天咱们不聊风花雪月,就来聊聊 Vue 3 里一个相当重要的工具——vue-tsc
。 别看它名字有点长,其实就是 TypeScript 的命令行工具,专门用来给 Vue 3 项目做类型检查和生成声明文件(.d.ts
)。
这玩意儿就像是咱们写代码时候的“老中医”,专门给代码“把脉”,看看有没有啥“病症”,比如类型不匹配、变量未定义等等。 还能自动生成说明书(.d.ts
),告诉别人你写的 Vue 组件怎么用,有哪些属性和方法。
那咱们今天就来深入扒一扒 vue-tsc
的工作原理和使用方法,保证各位听完之后,也能成为“老中医”,给自己的 Vue 3 项目好好“把把脉”。
一、vue-tsc
到底是个啥?
简单来说,vue-tsc
就是一个 TypeScript 编译器,但是它针对 Vue 3 做了优化,可以更好地处理 Vue 组件中的类型推断和模板类型检查。
你可以把它看作是 tsc
(TypeScript 官方编译器)的“升级版”,专门用来编译 Vue 3 + TypeScript 的项目。
它主要有两个功能:
- 类型检查 (Type Checking): 检查你的 Vue 组件、TypeScript 代码有没有类型错误,比如类型不匹配、属性不存在等等。
- 生成声明文件 (.d.ts): 根据你的 TypeScript 代码,自动生成
.d.ts
文件,用来描述你的组件的类型信息,方便其他开发者使用你的组件。
二、vue-tsc
的安装和配置
首先,确保你已经安装了 Node.js 和 npm(或者 yarn、pnpm)。
接下来,在你的 Vue 3 项目中安装 vue-tsc
:
npm install --save-dev vue-tsc
# 或者
yarn add -D vue-tsc
# 或者
pnpm add -D vue-tsc
安装完成后,你需要配置 tsconfig.json
文件,告诉 vue-tsc
如何编译你的项目。一个典型的 tsconfig.json
文件可能长这样:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"types": ["node"],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
},
"declaration": true, // 开启生成声明文件
"declarationDir": "./dist/types", // 声明文件输出目录
"noEmitOnError": true // 发现错误时不生成文件
},
"vueCompilerOptions": {
"experimentalTemplateCompilerOptions": {
"compilerOptions": {
"isCustomElement": (tag) => tag.startsWith('my-')
}
}
},
"include": ["src/**/*", "vite-env.d.ts"],
"exclude": ["node_modules"]
}
这里解释一下几个重要的配置项:
配置项 | 作用 |
---|---|
target |
指定编译的目标 JavaScript 版本,一般用 esnext ,表示使用最新的 JavaScript 语法。 |
module |
指定模块化规范,一般用 esnext ,表示使用最新的 JavaScript 模块化规范。 |
moduleResolution |
指定模块解析策略,一般用 node ,表示使用 Node.js 的模块解析策略。 |
strict |
开启严格模式,可以帮助你发现更多的潜在错误。 |
jsx |
指定如何处理 JSX 语法,一般用 preserve ,表示保留 JSX 语法,交给 Vue 编译器处理。 |
sourceMap |
生成 Source Map 文件,方便调试。 |
resolveJsonModule |
允许你直接引入 JSON 文件。 |
esModuleInterop |
允许你导入 CommonJS 模块,就像导入 ES 模块一样。 |
lib |
指定需要包含的类型声明文件,比如 esnext 表示包含最新的 JavaScript 类型声明,dom 表示包含 DOM API 的类型声明。 |
types |
指定需要包含的类型声明文件,比如 node 表示包含 Node.js API 的类型声明。 |
baseUrl |
指定模块解析的基准路径。 |
paths |
配置路径别名,方便你 import 模块。 |
declaration |
开启生成声明文件 (.d.ts)。 |
declarationDir |
指定声明文件输出目录。 |
noEmitOnError |
发现错误时不生成文件。 |
include |
指定需要编译的文件。 |
exclude |
指定需要排除的文件。 |
vueCompilerOptions |
Vue 编译器选项,可以配置一些 Vue 特有的编译选项,例如自定义元素。 |
experimentalTemplateCompilerOptions |
Vue 实验性的模板编译器选项,可以配置更底层的编译选项,例如自定义元素。 |
compilerOptions |
模板编译器的选项,比如自定义元素。 |
isCustomElement |
用于检查标签是否是自定义元素。 当返回 true 时,该标签不会被 Vue 视为一个组件,而是作为一个自定义元素处理。 |
三、vue-tsc
的使用方法
配置好 tsconfig.json
文件后,你就可以在命令行中运行 vue-tsc
命令了:
vue-tsc --noEmit # 只进行类型检查,不生成文件
vue-tsc --emitDeclarationOnly # 只生成声明文件,不生成 JavaScript 文件
vue-tsc # 进行类型检查,并生成 JavaScript 文件和声明文件
通常,我们会把 vue-tsc
命令添加到 package.json
的 scripts
中:
{
"scripts": {
"typecheck": "vue-tsc --noEmit",
"build:types": "vue-tsc --emitDeclarationOnly",
"build": "vue-tsc"
}
}
这样,你就可以使用 npm run typecheck
命令进行类型检查,使用 npm run build:types
命令生成声明文件,使用 npm run build
命令进行完整的编译。
四、vue-tsc
的类型检查能力
vue-tsc
的类型检查能力非常强大,它可以检查你的 Vue 组件中的各种类型错误,比如:
- Prop 类型错误: 检查你传递给组件的 prop 的类型是否正确。
- 事件类型错误: 检查你触发的事件的参数类型是否正确。
- 计算属性类型错误: 检查你的计算属性的返回值类型是否正确。
- 方法类型错误: 检查你的方法的参数类型和返回值类型是否正确。
- 模板类型错误: 检查你在模板中使用的变量和表达式的类型是否正确。
举个例子,假设你有一个组件 MyComponent.vue
:
<template>
<div>
<h1>{{ message }}</h1>
<button @click="handleClick">Click me</button>
</div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
message: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
});
const emits = defineEmits(['updateCount']);
const handleClick = () => {
emits('updateCount', '123'); // 错误:应该传递 number 类型
};
</script>
如果你运行 vue-tsc --noEmit
命令,vue-tsc
会提示你:
src/components/MyComponent.vue:20:18 - error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
20 emits('updateCount', '123'); // 错误:应该传递 number 类型
~~~~~
这个错误信息告诉你,你在触发 updateCount
事件时,传递了一个字符串类型的参数,但是它期望的是一个数字类型的参数。
五、vue-tsc
如何生成声明文件 (.d.ts)
vue-tsc
可以根据你的 TypeScript 代码,自动生成声明文件 (.d.ts),用来描述你的组件的类型信息。
声明文件可以告诉其他开发者你的组件有哪些 props、events、methods、slots 等等,方便他们使用你的组件。
举个例子,假设你有一个组件 MyComponent.vue
:
<template>
<div>
<h1>{{ message }}</h1>
<button @click="handleClick">Click me</button>
</div>
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
message: {
type: String,
required: true
},
count: {
type: Number,
default: 0
}
});
const emits = defineEmits(['updateCount']);
const handleClick = () => {
emits('updateCount', 123);
};
defineExpose({
handleClick
})
</script>
如果你运行 vue-tsc --emitDeclarationOnly
命令,vue-tsc
会生成一个 MyComponent.vue.d.ts
文件,内容如下:
import type { DefineComponent, PropType } from 'vue';
declare const _default: DefineComponent<{
message: {
type: PropType<string>;
required: true;
};
count: {
type: PropType<number>;
default: number;
};
}, {}, {}, {}, {}, {}, {}, {
message: {
type: PropType<string>;
required: true;
};
count: {
type: PropType<number>;
default: number;
};
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
"update-count": (arg: number) => true;
}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
message: {
type: PropType<string>;
required: true;
};
count: {
type: PropType<number>;
default: number;
};
}>> & {
"onUpdate-count"?: ((arg: number) => any) | undefined;
}, {
count: number;
}>;
export default _default;
这个声明文件描述了 MyComponent
组件的 props、events 等信息,方便其他开发者使用。
六、进阶技巧和常见问题
- 使用
/// <reference types="xxx" />
引入类型声明文件: 有时候你需要手动引入一些类型声明文件,比如第三方库的类型声明文件。你可以使用/// <reference types="xxx" />
语法来引入类型声明文件。 - 解决类型推断问题: 有时候
vue-tsc
无法正确推断类型,你需要手动指定类型。比如,你可以使用类型断言as
来指定类型。 - 忽略特定文件的类型检查: 有时候你希望忽略某些文件的类型检查,比如一些测试文件或者示例代码。你可以在
tsconfig.json
文件的exclude
字段中排除这些文件。 - 自定义 Vue 编译器选项: 你可以通过
vueCompilerOptions
字段来配置 Vue 编译器选项,比如自定义元素、自定义指令等等。 - 使用 Volar 插件: Volar 是一个 Vue 3 的 VS Code 插件,它可以提供更好的类型检查和代码提示功能。
七、总结
vue-tsc
是 Vue 3 + TypeScript 项目中一个非常重要的工具,它可以帮助你发现类型错误,生成声明文件,提高代码质量和可维护性。
希望今天的讲解能够帮助大家更好地理解和使用 vue-tsc
。
最后,送给大家一句“码农箴言”:“代码虐我千百遍,我待代码如初恋。” 祝大家编码愉快!