[译]<<Effective TypeScript>> 技巧51:用镜像类型去切断依赖

205 阅读2分钟

本文的翻译于<<Effective TypeScript>>, 特别感谢!! ps: 本文会用简洁, 易懂的语言描述原书的所有要点. 如果能看懂这文章,将节省许多阅读时间. 如果看不懂,务必给我留言, 我回去修改.

技巧51:用镜像类型去切断依赖

假定你在写一个库用来解析CSV文件。你传入CSV文件的内容,返回一个对象构成的数组。为了使用方便,你允许传入内容可以是string或者NodeJS Buffer:

function parseCSV(contents: string | Buffer): {[column: string]: string}[]  {
  if (typeof contents === 'object') {
    // It's a buffer
    return parseCSV(contents.toString('utf8'));
  }
  // ...
}

Buffer类型来自于 NodeJS 的type声明,这样安装:

npm install --save-dev @types/node

当你发布你的CSV解析库,你将node的type声明加入依赖。那么会有两拨人会对这个声明依赖有抱怨:

  • 想知道自己@types依赖的js开发者
  • 想知道自己为啥会依赖NodeJs的ts web开发者:

这样的抱怨是合理的。Buffer的行为没有必要的,它只和NodeJS的使用者相关。

与其依赖node的type声明,不如自己写:

interface CsvBuffer {
  toString(encoding: string): string;
}
function parseCSV(contents: string | CsvBuffer): {[column: string]: string}[]  {
  // ...
}

我们写的CsvBuffer类型,比完整的CsvBuffer类型更短。但是它确实满足了我们的需要(因为我们只要Buffer的toString方法)。当我们传入Buffer,类型是安全的:

parseCSV(new Buffer("column1,column2\nval1,val2", "utf-8"));  // OK

如果我们的库依赖其他库的类型声明,与其用他的实现,不如我们将我们需要的类型进行镜像复制。这样减少了依赖,能提升其他人的开发体验。

当然如果我们依赖其他库的type声明特别多,那我们应该标注出来来来关系。

这个技巧对应写单元测试的小伙伴同样有效。