Vue3全局注册组件报JSX元素类型无构造/调用签名lint错误
问题描述
- 项目所有功能运行正常,组件可正常使用,应用构建流程无异常,但VS Code编辑器持续抛出lint错误:
JSX element type 'X' does not have any construct or call signatures,注册自定义组件时也会触发相同报错 - 问题在Electron搭建的项目中出现,使用Vue官方CLI创建全新项目也可复现
- 开发设备为全新装机,所有依赖均为问题出现当日安装
环境版本信息
- Vue: v3.2.36
- Vite: v2.9.9
- Node: v18.3.0
- NPM: v8.11.0
相关代码
入口文件 client.ts
重命名为main.ts无法解决问题,代码如下:
import { createApp } from "vue"; import App from "./App.vue"; import { Icon } from "@vicons/utils"; import { NButton, NCard, NTabs, NTabPane, NInput, NInputNumber, NSelect, NDataTable, NButtonGroup, NScrollbar, NModal, } from "naive-ui"; const app = createApp(App); app.component("Icon", Icon) .component("Button", NButton) .component("Card", NCard) .component("Tabs", NTabs) .component("TabPane", NTabPane) .component("Input", NInput) .component("InputNumber", NInputNumber) .component("Select", NSelect) .component("DataTable", NDataTable) .component("ButtonGroup", NButtonGroup) .component("Scrollbar", NScrollbar) .component("Modal", NModal) .mount("#app");
tsconfig.json 配置
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, "lib": ["esnext", "dom"], "paths": { "@components": ["./components"], "@domain": ["./domain"], "@helpers": ["./helpers"], "@views": ["./views"] } }, "include": ["./**/*.ts", "./**/*.d.ts", "./**/*.tsx", "./**/*.vue"] }
相关截图
- Lint报错截图:

- 终端警告截图:

报错原因
该报错属于TypeScript类型校验层面的误报,和业务代码运行逻辑无关:Vite/Vue CLI构建时会通过内置插件完成Vue组件的转译处理,因此构建、运行环节都不会出问题,但VS Code的TS语言服务没有拿到正确的Vue组件类型声明,无法识别JSX语法下的Vue组件构造签名,就会抛出该错误。终端的警告也是同源问题,提示TS未正确配置Vue JSX解析规则。
核心触发点有三个:
- 项目缺失Vue专属的类型声明文件,TS无法识别
.vue后缀的单文件组件类型 - tsconfig未配置Vue对应的JSX解析规则,TS按原生JSX语法校验Vue模板
- VS Code插件冲突(Vetur和Volar同时启用),或使用了VS Code内置的TS版本而非工作区安装的版本,类型解析逻辑不匹配Vue3要求
解决方案
按以下步骤操作即可修复:
- 在项目根目录新建
env.d.ts类型声明文件,写入以下内容,补齐单文件组件、全局注册组件的类型定义:
/// <reference types="vite/client" /> declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent<Record<string, unknown>, Record<string, unknown>, any> export default component } // 声明全局注册的组件类型,消除全局组件的lint报错 declare module 'vue' { export interface GlobalComponents { Icon: typeof import('@vicons/utils')['Icon'] Button: typeof import('naive-ui')['NButton'] Card: typeof import('naive-ui')['NCard'] Tabs: typeof import('naive-ui')['NTabs'] TabPane: typeof import('naive-ui')['NTabPane'] Input: typeof import('naive-ui')['NInput'] InputNumber: typeof import('naive-ui')['NInputNumber'] Select: typeof import('naive-ui')['NSelect'] DataTable: typeof import('naive-ui')['NDataTable'] ButtonGroup: typeof import('naive-ui')['NButtonGroup'] Scrollbar: typeof import('naive-ui')['NScrollbar'] Modal: typeof import('naive-ui')['NModal'] } } export {}
- 修改
tsconfig.json的compilerOptions字段,补充JSX解析、类型跳过相关配置,修改后完整配置如下:
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "jsxImportSource": "vue", "sourceMap": true, "resolveJsonModule": true, "esModuleInterop": true, "skipLibCheck": true, "lib": ["esnext", "dom"], "types": ["vite/client"], "paths": { "@components": ["./components"], "@domain": ["./domain"], "@helpers": ["./helpers"], "@views": ["./views"] } }, "include": ["./**/*.ts", "./**/*.d.ts", "./**/*.tsx", "./**/*.vue"] }
- 处理VS Code环境问题:
- 禁用Vetur插件,安装并启用官方Vue3插件
Vue - Official(原Volar) - 按下快捷键
Ctrl+Shift+P(Windows)/Cmd+Shift+P(Mac)调出命令面板,执行TypeScript: Select TypeScript Version,选择「使用工作区版本」,不要使用VS Code内置的TypeScript - 再次调出命令面板,执行
TypeScript: Restart TS Server重启TS语言服务
操作完成后所有lint报错和终端警告都会消失。
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

