- 说下写这个文章的起因:我之前写了一个类型判断的库,是基于js写的而且只是支持commonJs引入模式,所以就想着改造下,可以用ts写而且必须支持esm以及commonJs。在这个过程有一些注意事项想简单记录下。
- 同时也希望帮助到一些同学。本文章比较适合工作2~3年以内,或是没有接触过ts+工具的同学
https://github.com/a572251465/where-type
本文将从一个写插件的角度来做阐述
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()
]
}
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
}
到现在为止我们所做的事情远远没有结束。之前的都是通用的“开胃菜”,接下来重点来了。重点集中在二个地方:package.json/ index.d.ts
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
呢
tsconfig.ts
文件中属性esModuleInterop
一起使用export default types
也是可以的,但是使用的需要types.default.isNumber
来使用了(这个可以通过打包配置解决)export default types
跟 export = types
是保持一致的,但是后者会更好点"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支持下我哦