我是靠谱客的博主 昏睡曲奇,最近开发中收集的这篇文章主要介绍使用 TypeScript 的 CheckJS 为你的陈旧 JavaScript 项目续命,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

???? Why CheckJS?

  • 让 JavaScript 项目也能享受到 TS 的类型推导等诸多好处。* 和直迁 TypeScript 相比,大大降低成本和风险,例如:???? 使用方法

安装依赖、追加配置

# 为你的项目安装 TypeScript
npm install typescript

# 可选的:类型定义文件,按照自己的项目需要酌情添加
npm install @types/react -D 

根目录新建 tsconfig.json,复制以下内容,特别注意黄色加粗的内容:

{"compilerOptions": {"outDir": "./FAKE_DIR","target": "ESNext","module": "CommonJS","esModuleInterop": true,"allowJs": true,"checkJs": true,"strictNullChecks": true,"jsx": "react"},"include": [// 根据项目目录结构自行配置"./src/**/*"],"exclude": [// 根据项目特性按需添加]
} 

编写类型定义

编写类型定义的时候最好有一定的约束,可以防止类型定义冲突、提高代码结构可读性,我个人推荐下面这些方案。

目录结构

一般来说,类型定义都是针对一个页面或者组件的(我们可以拿 CSS 样式文件的地位来做类比),即和组件(页面)所在文件在同一目录下,命名为 typings.d.ts:

└── src└── pages├── detail│   ├── components│   │   └── Alert│   │   ├── index.jsx│   │   ├── style.scss│   │   └── typings.d.ts│   ├── index.jsx│   ├── style.scss│   └── typings.d.ts├── home└── profile 

书写细节

d.ts 文件和 ts 文件一个最大的不同就是前者无需导入,可以理解为全局变量,这就很容易导致同名类型定义的冲突干扰,为了尽可能地解决该问题,推荐使用 namespace (命名空间)语法来分组局部类型定义,还是以上面一小节的目录结构为例,Alert 组件的 typings.d.ts 可以这样写:

declare namespace Page.Detail.Components.Alert { interface AlertProps {/** * 警告内容 */message: string;/** * 当关闭时做些什么 */onClose: () => void;}
} 

原则是根据其所属的页面、组件等层级关系划分,层级之间可以用点号隔开,以防止过多的嵌套影响美观。

其他的书写细节和 TypeScript 的写法别无二致,平时 ts 怎么写的,这里如法炮制即可。

消费方式

核心思路是通过编写 jsdoc 进行消费,下面提供几个不错的实践:

案例 1:React 函数式组件

下面的案例中使用了 React.FC 工具函数来实现。(提示:TypeScript 的各种内置 Utility Types 也是可以利用起来的)

/**
 * Alert 组件,用来展示警告信息,如:网络错误、服务器错误等
 *
 * @type {React.FC<Page.Detail.Components.Alert.AlertProps>}
 */
export const Alert = (props) => {const { message, onClose } = props;return <div>hello world!</div>;
}; 
案例 2:普通函数

对于一般函数,使用 @param 或者 @returns 注释描述该函数的入参和返回值。

/**
 * 获取用户信息描述
 *
 * @param {Page.Detail.Components.Alert.UserInfo} userInfo 用户信息
 * @return {string} 用户信息描述
 */
const getUserDescription = (userInfo) => {const {name, age} = userInfo;return `我是 ${name}, 今年 ${age} 岁`;
} 
案例 3:一般变量

对于一般变量,可以使用 @types 注释在该变量顶部描述:

/** @type {Page.Detail.Components.Alert.UserInfo} */
const userInfo = {age: 18,name: '张三',
}

// 或者也可以这样写
const user = /** @type {Page.Detail.Components.Alert.UserInfo} */ {age: 18,name: '张三',
};

// 在 return 语句中
return /** @type {Page.Detail.Components.Alert.UserInfo} */ {age: 18,name: '张三',
}; 

最后,配合 VSCode、WebStorm 等现代 IDE,你就可以享受到类型提示了!

???? 使用时的陷阱

无法识别 d.ts 中定义的 namespace

先引入一个问题:

已知某项目是一个巨大的 monorepo,请看它的 tsconfig.json,它有什么潜在的问题?

{"compilerOptions": {"outDir": "./FAKE_DIR","target": "ESNext","module": "CommonJS","esModuleInterop": true,"allowJs": true,"checkJs": true,"jsx": "react"},"include": ["./packages/**/*","./typings"]
} 
  • 大部分情况下,monorepo 仓库下的构建产物(大部分是特别长的 JavaScript 文件)都会被打包到各自 package 下面,很容易被 include 字段匹配。* 一旦开启 allowJs = true,TypeScript Server 就会去检查这些不必要的 JavaScript 文件,从而触发性能阈值失去某些 feature,例如我们上文的 JavaScript Check 能力。

那么如何去看是什么文件造成了此问题?这里提供一个非常优雅的解法:

  • 首先打开 TS Sever Log:
  • 在大概第三十行左右的位置就可以看到 TypeScript Checker log 了所有被解析的 build 产物,这些都应该被排除在外:

在上面这个 Case 中,就可以通过 exclude 字段排除掉所有的 build 目录来提高性能:

{"compilerOptions": { // 略去},"include": ["./packages/**/*","./typings"],"exclude": ["**/build/**"]
} 

最后

为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

最后

以上就是昏睡曲奇为你收集整理的使用 TypeScript 的 CheckJS 为你的陈旧 JavaScript 项目续命的全部内容,希望文章能够帮你解决使用 TypeScript 的 CheckJS 为你的陈旧 JavaScript 项目续命所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(51)

评论列表共有 0 条评论

立即
投稿
返回
顶部