本文是系列文章, 作者一个橙子pro,本系列文章大纲如下。转载或者商业修改必须注明文章出处
一、申请npm账号、个人包和组织包区别
二、了解 package.json 相关配置
三、 了解 tsconfig.json 相关配置
四、 api-extractor 学习
五、npm
包制作完整教程,我的第一个npm包
在最早的typescript
官方表述当中说,typescript
1是一个JavaScript
超集,当时有一些代替JavaScript
的內味在里面,并且发布了像接口、枚举这些JavaScript
不存在的类型。但是随着时间的推移,这个表述发生了变化,typescript
是一个JavaScript
类型标注语言。可以看得出,typescript
对于自己的定位是类型推断,而不是替代JavaScript
。
常见的文件末尾.d.ts
结尾的文件,我们的代码工具会识别他是一个typescript
类型文件。而项目根目录存在tsconfig.json
则表示他是一个可以支持typescript
的项目。对于编译器和编辑器而言,正是因为这个文件的存在,它们才能识别这是一个ts
项目,并且给与完整的typescript
语法识别。事实上,在项目根目录创建jsconfig.json
,同样获得大部分ts
开发上的一些体验。
本示例完整代码发布在这里:https://github.com/vue3plugin/npm-pkg-by-vite,有dev
和main
两个分支提供参考。
对于这个例子而言,可能好多配置没有,同样下面示例涉及的配置我也不会逐个介绍,只介绍一些特别常用到的,完整配置参见2。由于打包工具的存在,我们的
ts
通常只用于开发阶段的类型检查,以及对外输出的类型文件。对于它打包ts
代码的能力,我们通常直接使用打包工具代替了。
文件tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"lib": [
"ESNext",
"DOM",
"DOM.Iterable",
],
"moduleResolution": "Bundler",
"sourceMap": true,
"skipLibCheck": true,
"inlineSources": false,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"removeComments": true,
"alwaysStrict": true,
"noImplicitUseStrict": false,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": false,
"strictNullChecks": false,
"forceConsistentCasingInFileNames": true,
"checkJs": false,
"allowJs": true,
"esModuleInterop": true,
"importHelpers": false
},
"include": ["./src/**/*", "env.d.ts", ],
"exclude": ["node_modules/**/*"]
}
对于每一个typescript
版本而言,配置上多是增加或减少了一些配置项,其余或是一些typescript
类型推断的新支持,大多数常见的配置,还是不变的。
这个设置是表示typescript
在打包编译的时候,编译的目标版本。例如这个值是ES5
,则ts
编译之后会是ES5
的代码。实际上在真正的工程当中我们用不到他,无论是webpack
、rollup
、vite
编译目标ts
的时候,会直接借用插件移除ts
相关类型,经过自己加工,根据打包工具的内置方法去做一些编译目标。目前大多借用core.js
这个polyfill
仓库去做一些代码降级,例如把ES6
降级为ES5
。
当前编辑器内写代码所使用的代码规范,还有好多AMD
,CommonJS
等其他规范,目前一致推崇的是ES
相关的语法,我可能比较激进,直接ESNext
,以便于体验最新的ES
语法
这个就比较更加常用了,我们在写ts
代码的时候,通常会有若干原生代码的提示。我们写const
、let
这些声明,或者一个for...of...
语法的提示,这些都来自这里的设置。这个参数的值是一个数组,像上边的例子ESNext
表示导入可ES
相关语法,DOM
表示导入了浏览器一些相关的Api,例如常见的document
、window
等。我们开发vue
这种web
项目的时候,这两个都是必选的。不过通常脚手架都已经帮我们设置好了。
这个表示模块解析策略,这个值大白话使用node的解析方式,区别在于使用的是哪个版本的node
。
classic
仅在ts 1.6
版本之前使用,当前可以完全被忽略
node10
表示一个旧的版本,只可以使用CommonJS
的语法
node16
和nodeNext
:由于node12+
的版本早已同时支持 ECMAScript
导入和 CommonJS
,当他的值是node16
和nodeNext
时,我们大可以在代码当中同时使用两种语法,import ... from ...
或者 require('xxx')
。
bundler:bundler
和node16
和nodeNext
是相似的配置,这个值我在5.1.6
版本看到,大致是个新的配置,这个配置项在任何时候不需要文件后缀名的声明。
当然这个配置是有坑在里面的,我们知道,package.json
有个type的参数,详见【制作npm包2】了解 package.json 相关配置 里面的介绍。当我们设置值为module
时,实际上我们的代码是就不会支持require
的导入,尤其是我们在使用诸如vite
、rollup
这类只支持es
的打包方式,尽管typescript
语法上支持是没有用的。
表示当前支持js
文件的类型检查
允许代码当中出现js代码的导入
代码当中对于无法推断的配置项,将用any
类型替代。
禁止在索引到对象时报告有关隐式 any 的错误,一个对象使用索引的方式去取值,在默认ts
配置当中是不允许的。实际上,这个配置也不是建议的。
例如:
const obj = { name : '一个橙子pro' }
// Element implicitly has an 'any' type because expression of type '"obj "' can't be used to index type '{ name : string; }'.
obj['name'] // 当开启 suppressImplicitAnyIndexErrors 配置,才可以这样取值
obj.a //正确的写法
对于开启noImplicitAny
来说,suppressImplicitAnyIndexErrors
这个配置也就默认开启了。一般而言,不开启这些有些反类型的开关,对后期代码维护更加友好一些。
表示ts
项目包含哪些目录,只有当前目录都包含在这个选项当中,我们的代码提示才会生效。
包含一些通配符的语法:
*
匹配零个或多个字符(不包括目录分隔符)?
匹配任何一个字符(不包括目录分隔符)**/
匹配嵌套到任何级别的任何目录表示ts
项目需要排除哪些目录,一般排除node_modules
就行,通配符语法和include
完全相同。
下面是介绍一些和类型打包有关的配置,简略介绍了。一般打包的时候,我们会专门写一个打包类型的文件。
文件tsconfig.types.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"declaration": true, /* 生成相关的 '.d.ts' 文件。 */
"declarationDir": "./dist/types", /* '.d.ts' 文件输出目录 */
"emitDeclarationOnly": true, /* 只生成声明文件,不生成 js 文件*/
"rootDir": "./src", /* 指定需要编译的文件目录(用于输出),用于控制输出目录结构 */
},
"include": [
"src"
],
}
emitDeclarationOnly
这个配置项设置为true
,正好接应上边的描述,我们的ts
配置只进行代码提示,以及类型文件打包的工作。
由于大多数配置和上面相同,这里用到了extends
这个参数,extends
字如其名,表示继承一个ts
的配置文件。
typeScript 英文文档, 中文文档 ↩︎
https://ts.nodejs.cn/tsconfig ↩︎