vue-tsc-ci

test12026-10-2513 次阅读

为什么 tsc 不够

tsc 不认识 .vue 单文件组件,直接用 tsc 跑类型检查会跳过所有 vue 文件。vue-tsc 是 Vue 官方的类型检查器,底层复用 TypeScript,能解析 SFC 的 script、props、emits 和模板。把它放进 CI,就能在合并前拦住类型错误。

配置 tsconfig

关键点是 types 里带上 vite/client,并用 moduleResolution: Bundler 匹配 Vite 的解析规则。

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "strict": true,
    "jsx": "preserve",
    "lib": ["ESNext", "DOM"],
    "types": ["vite/client"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue", "env.d.ts"]
}

加上 vue 文件的类型声明

env.d.ts 里给 .vue 一个模块声明,否则 TS 会在 import 组件时报找不到模块。

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

declare module "*.vue" {
  import type { DefineComponent } from "vue";
  const component: DefineComponent<{}, {}, any>;
  export default component;
}

脚本拆成 typecheck 与 build

把类型检查从构建里拆出来单独跑,CI 失败信息更聚焦,本地也能先 typecheck 再 build。

{
  "scripts": {
    "typecheck": "vue-tsc --noEmit",
    "build": "vue-tsc --noEmit && vite build"
  }
}

组件里把 props 和 emits 都标上类型

defineProps 用接口、defineEmits 用类型化调用签名,模板里就能拿到完整的类型提示与校验。

<script setup lang="ts">
interface Props {
  title: string;
  count?: number;
}
const props = defineProps<Props>();

const emit = defineEmits<{
  (e: "increment", value: number): void;
}>();

function onClick() {
  emit("increment", (props.count ?? 0) + 1);
}
</script>

<template>
  <button @click="onClick">{{ title }}: {{ count ?? 0 }}</button>
</template>

CI 里跑一道

把 typecheck 放进 GitHub Actions,push 和 PR 都拦一遍,类型错误就进不了主干。

name: typecheck
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm run typecheck

类型检查是花钱最少的一道质量闸门,值得每次提交都跑。

T

test1

文章作者

为什么 tsc 不够 tsc 不认识 .vue 单文件组件,直接用 tsc 跑类型检查会跳过所有 vue 文件。vue...

分类
技术
发布时间
2026-10-25
字数
约 1837 字
阅读
13 次