前言
- 说下写这个文章的起因:我之前写了一个类型判断的库,是基于js写的而且只是支持commonJs引入模式,所以就想着改造下,可以用ts写而且必须支持esm以及commonJs。在这个过程有一些注意事项想简单记录下。
- 同时也希望帮助到一些同学。本文章比较适合工作2~3年以内,或是没有接触过ts+工具的同学
参照源码地址
https://github.com/a572251465/where-type
开始
本文将从一个写插件的角度来做阐述
1. 该如何配置打包呢
- 首先我们要明确一点,我们是希望有esm 以及mjs。所以我们在打包的时候需要配置多个出口文件,每个文件对应不同的模块方式,接下来看下详细的rollup代码
const path = require('path')
const { nodeResolve } = require('@rollup/plugin-node-resolve')
const commonjs = require('@rollup/plugin-commonjs')
const ts = require('@rollup/plugin-typescript')
const { babel } = require('@rollup/plugin-babel')
const { terser } = require('rollup-plugin-terser')
const del = require('rollup-plugin-del')
const resolvePath = (url) => path.resolve(__dirname, url)
module.exports = {
input: resolvePath('../src/index.ts'),
output: [
{
file: resolvePath('../dist/index.cjs.js'),
format: 'cjs',
exports: 'default'
},
{
file: resolvePath('../dist/index.esm.js'),
format: 'esm',
exports: 'default'
}
],
plugins: [
del(),
ts(),
nodeResolve(),
commonjs(),
babel({ babelHelpers: 'bundled' }),
terser()
]
}
- 其实通过上述代码可以看到参数【output】中是配置了两个出力,对应的不同的模式。这样在使用的时候即可以满足esm也可以满足mjs了
2. 那该怎么编写代码呢
import types from 'where-type'
// OR
import {_} from 'where-type'
// OR
import {isDate} from 'where-type'
- 上述的代码其实就是我想让别人使用的方式。我希望他们是这么用的,在
import
的时候给与很好的提示,接下来我们看下源代码
const obj: Record<string, string> = {}
const isType = function isType(type: string) {
const params = String(type).toLocaleLowerCase()
return function specificType<T>(value: T): boolean {
const judgeType = `[object ${params}]`
const resultType = obj.toString.call(value).toLocaleLowerCase()
return judgeType === resultType
}
}
const isNumber = isType('Number')
const isBoolean = isType('Boolean')
const isString = isType('String')
const isNull = isType('Null')
const isObject = isType('Object')
const isUndefined = isType('Undefined')
const isFunction = isType('Function')
const isArray = isType('Array')
const isDate = isType('Date')
const isError = isType('Error')
const isRegExp = isType('Function')
const isSymbol = isType('Symbol')
const isMath = isType('Math')
const isJson = isType('Json')
const getTypes = function getTypes<T>(value: T | T[]): string[] {
// 判断是否是数组
if (isArray(value)) {
return (value as T[]).map((item) => {
const execRes = /\s+([a-zA-Z]+)/gi.exec(obj.toString.call(item))!
const firstWorld = execRes[0].trim().toLocaleLowerCase()
return firstWorld
})
}
const result = getTypes([value])
return result
}
const _ = {}
const allTypes = [
'Number',
'Boolean',
'String',
'Null',
'Object',
'Undefined',
'Function',
'Array',
'Date',
'Error',
'Function',
'Symbol',
'Math',
'Json'
]
let i = 0
for (; i < allTypes.length; i += 1) {
const iden = allTypes[i]
const field = `is${iden}`
if (!Reflect.has(_, field)) {
Object.defineProperty(_, `is${iden}`, {
value: isType(iden),
enumerable: false,
writable: false
})
}
}
export default {
isNumber,
isBoolean,
isNull,
isString,
isObject,
isUndefined,
isFunction,
isArray,
isDate,
isError,
isRegExp,
isSymbol,
isMath,
isJson,
_,
getTypes
}
3. 以为这样就结束了吗??
到现在为止我们所做的事情远远没有结束。之前的都是通用的“开胃菜”,接下来重点来了。重点集中在二个地方:package.json/ index.d.ts
3.1 怎么来写我们的库声明文件
- 首先我们要知道声明文件的查找方式,这样才能明白应该在哪定义
- 给
package.json
中的属性types
或是typings
指定一个类型声明地址 - 上述不满足的话,可以在输出文件的同目录下写一个
index.d.ts
- 上述不满足的话,可以使用
node_modules
下的@types/xxx
下的声明文件
- 给
- 也许有人说了:“说了这么多了能不能举个例子”:
types/index.d.ts
interface ITypes<T = IFn<IType>> {
isNumber: T
isBoolean: T
isString: T
isNull: T
isObject: T
isArray: T
isDate: T
isError: T
isFunction: T
isSymbol: T
isMath: T
isJson: T
_: Omit<ITypes, '-'>
getTypes: (value: IType | any[]) => string[]
}
declare const types: ITypes
declare const _: ITypes
export { _ }
export = types
- 上述的内容就是该插件的声明文件。我们需要使用关键字
declare
将我们声明的类型暴露到外面去。但是这里有个注意点,为什么是export = tyeps
呢- 其实这个是ts中独有语法,可以任意转换到esm/ commonjs去。但是也会有前提是:必须配置
tsconfig.ts
文件中属性esModuleInterop
一起使用 - 当然如果你直接写
export default types
也是可以的,但是使用的需要types.default.isNumber
来使用了(这个可以通过打包配置解决) - 总结出一句话
export default types
跟export = types
是保持一致的,但是后者会更好点
- 其实这个是ts中独有语法,可以任意转换到esm/ commonjs去。但是也会有前提是:必须配置
3.2 那package.json有哪些注意事项呢
"files": [
"dist/*.js",
"types/*.d.ts"
],
"typings": "types/index.d.ts",
"main": "./dist/index.cjs.js",
"module": "./dist/index.esm.js",
"repository": {
"type": "git",
"url": "https://github.com/a572251465/where-type.git"
},
"bugs": {
"url": "https://github.com/a572251465/where-type/issues"
},
"homepage": "https://github.com/a572251465/where-type",
"keywords": [
"type",
"is-type",
"Number, String, Boolean"
]
- 字段
files
,表示发包的时候需要上传哪些文件 - 字段
typings
, 表示我们引用的声明类型文件应该到哪里找 - 字段
main
, 当引用方式是commonJs的时候,应该使用哪个js文件 - 字段
module
, 当引用方式是esm的时候,应该使用哪个js文件 - 其余的都是常规的一些配置项了
结束
上述的分享结束。其实知识可以说不难而且很简单。如果你是小白,可能会帮助您大忙。如果觉得我写的还有用处的话,可以在GitHub中点击star支持下我哦