当ts遇到工具库的时候,我们应该注意哪些事项

前言

  • 说下写这个文章的起因:我之前写了一个类型判断的库,是基于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 typesexport = types是保持一致的,但是后者会更好点

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支持下我哦

你可能感兴趣的:(工程化,websocket,网络,http)