深入理解 Vue 3 的 `vue-tsc` (TypeScript 命令行工具) 如何进行类型检查和生成声明文件 (`.d.ts`)。

各位观众老爷们,大家好!我是今天的主讲人,江湖人称“码农老王”。今天咱们不聊风花雪月,就来聊聊 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 的项目。

它主要有两个功能:

  1. 类型检查 (Type Checking): 检查你的 Vue 组件、TypeScript 代码有没有类型错误,比如类型不匹配、属性不存在等等。
  2. 生成声明文件 (.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.jsonscripts 中:

{
  "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

最后,送给大家一句“码农箴言”:“代码虐我千百遍,我待代码如初恋。” 祝大家编码愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注