Typescript
TypeScript 也是工程化的重要一环,在面对复杂功能代码设计的时候,足够熟悉 TS 能够帮我们更加安全快速地实现。
关于 TS 有数不尽的教程,所以在假设您已经掌握基本语法的情况下,让我们开始探索一些有趣的东西。
附上一篇教程: https://wangdoc.com/typescript/
tsc
tsc 是 TypeScript 官方的命令行编译器,拥有编译,检查,生成类型定义文件的功能
$ tsc src/*.ts上面的命令就可以将 TS 文件编译为 JS 文件,但是在前端功能中,我们很少会使用这个功能,而是采用其他工具,例如 rollup、esbuild 等进行文件等转换:
$ esbuild src/*.ts --outdir=dist在前端工程中,tsc 的用途通常是进行 TS 的类型校验,因为上面的工具例如 esbuild 只进行文件类型转换,抹去 TS 类型,而不做任何类型校验。
例如我们通常会在 scripts 加上这段脚本,仅仅对类型进行校验,--noEmit 的作用是不生成编译产物,只进行类型检查
{
"scripts": {
"typecheck": "tsc --noEmit"
}
}dts生成
对应一般情况,可以使用 tsup 的生成功能
$ tsup src/index.ts --dtsOnly或者是直接使用 tsc
$ tsc src/index.ts --emitDeclarationOnly --declaration --outDir dist
$ tsc src/index.ts --emitDeclarationOnly --declaration --outFile ./index.d.ts # 合并成一个文件类似的,有 johnsoncodehk/vue-tsc 来支持 vue 相关的 dts 生成
$ vue-tsc src/index.ts --emitDeclarationOnly --declaration --outDir dist
$ vue-tsc src/index.ts --emitDeclarationOnly --declaration --outFile ./index.d.ts # 合并成一个文件至于 JS 和 SouceMap 等产物的生成,交由打包工具去生成,我们仅用 tsc 进行类型检查
扩展类型
在 NodeJs 中,我们通过安装 @types/node 来获得 NodeJs 环境 API 的类型提示
但是如果我们想扩展一个类型怎么办呢,譬如为环境添加 process.env.NODE_ENV,原生环境中是不存在这个变量的
借助于 TS 中两个同样的 interface 声明会被合并的特性,就可以实现扩展
interface IPeople {
name: string
}
interface IPeople {
age: number
}
let o: IPeople = {
name: 'mike',
age: 10
}但是 process.env.NODE_ENV 是一个嵌套的对象,所以需要找到 ProcessEnv 类型定义所在的命名空间,在进行扩展
通过 declare 关键字,扩展 ProcessEnv 类型
declare global {
namespace NodeJs {
interface ProcessEnv {
NODE_ENV: 'development' | 'production'
}
}
}
// 扩展 window 的类型
declare global {
interface window {
time: number;
}
}类型声明
如上面所展示的,借助 declare,我们可以不必在变量定义的时候就定义类型。所以类似的,除了扩展类型,还可以定义类型
foo = 2
declare let foo: number
// 或者是函数
declare let bar: () => number
bar()扩展模块类型
某些模块,比如某些 NPM 包,没有提供类型声明文件,我们可以扩展模块的类型,定义里面的模块的类型
declare module 'module1' {
function log(): string
}
declare module 'module2' // 声明后,默认导出默认是 anyimport m_1 from 'module1'
import m_2 from 'module2'
m_1.log()以此来消除 TS 错误
package.json 的 types 字段
在 发布 NPM 包这一节中,提到了在 package.json 中添加 types 字段,指明一个 .d.ts 文件,就可以为当前模块定义类型了。
Details
{
"name": "transform-size-data",
"version": "1.0.0",
"type": "module",
"types": "./dist/index.d.ts",
"author": "peterroe",
"module": "./dist/index.mjs",
"main": "./dist/index.cjs",
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./dist/index.mjs"
}
}
}本质上就是隐式地声明了 declare module 'transform-size-data',来定义类型的,让使用者能够获得正确的类型
declare module 'transform-size-data' {
// ./dist/index.d.ts 的内容
}tsconfig.json
这里有一份较为详细的 tsconfig.json 说明,这些配置除了给 tsc 读取,其他打包工具也会使用其中的某些字段
下面只介绍一些常用的字段
target
target 指定编译出来的 JavaScript 代码的 ECMAScript 版本,一般设置为 esnext。(esbuild 依赖)
{
"compilerOptions": {
"target": "esnext"
}
}