个人技术分享

这一段时间在为华为云的 Vue DevUI 组件库(一个前端组件库)做开源贡献。每次在 VSCode 中打开整个项目的时候都发现里面所有.tsx结尾的文件都是大面积爆红,我查看了一下报错内容:JSX 元素隐式具有类型 "any",因为不存在接口 "JSX.IntrinsicElements"。

作为一个晚期的强迫症患者,看到这个情况,这能忍?虽然其实这并不影响使用,但是每每想到我的代码中到处都是爆红,实在是令人头皮发麻。

于是我立刻把报错内容复制粘贴,在必应上四处搜寻,不少博客都建议我安装@types/react@types/react-dom,但是我们的组件库是 Vue JSX,而和 Vue 相关的博客里,得到的结论都是清一色的“不使用严格的类型检查”。

要么是:

{
  "compilerOptions": {
    "strict": false
  }
}

这个是禁用严格检查,意思是让检查器对你宽容一些,一些小问题就别 cue 我了。

要么是:

{
  "compilerOptions": {
    "noImplicitAny": false,
  }
}

这个倒是更加一针见血,是禁用在出现表达式和声明上有隐含的any的时候抛出异常,让它对类似的异常忽略。它直接针对我们遇到的这个问题,让这类问题被忽略掉。好吧,你这边给我报这个错误,报错报的很好,以后别报了

实际上本质上上面这两个其实解决方案是一个,都是降级代码检查的严格程度。要硬说这两种都的确都是有效解决方案,但是实在是略有些简单粗暴,没有任何优雅性可言。更何况我提交一个把strict改成false的 PR 的话,感觉还是略有些生草。

后来我又想到可以配置@vue/babel-preset-jsx,但是这个也没有解决JSX语法报错的问题(我怀疑可能是依赖不匹配的问题),最后我还是想到了一个稍微优雅一些的方案:

// src/shims-vue.d.ts
import { VNode } from 'vue';

declare type VueNode = VNode;
declare global {
  namespace JSX {
    interface IntrinsicElements {
      [elem: string]: unknown;
    }
  }
}

这里使用unknown是因为 TypeScript 非常排斥开发者使用一个宽泛的类型声明,接受任何类型的相关值,所以我没有使用any而是使用了官方推荐的unknown作为替代。

这个文件可以放在任何一个src路径中,由于 DevUI 是一个组件库,所以我将它放在了外层的根目录中。实际上,这里使用了global声明,这并不影响你将它放在任何特定位置,只要确保这个路径会被检查器识别即可。