[译]<<Effective TypeScript>> 技巧61:一个模块一个模块地转换你的依赖图

235 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

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

技巧61:一个模块一个模块地转换你的依赖图

当你已经用让了先进的js语法,也将ts纳入你的构建链,同时也能通过你所有的单元测试。那问题来了,该从哪开始将你的js转换成ts呢?

当你给一个模块添加了type,很有可能所有依赖该模块的模块将会报错。理想情况是你一个模块一个模块的去添加type。 这就好像,从依赖图的叶子节点慢慢修改到根节点。

第一个应该迁移的模块应该是第三方依赖。因为你依赖了它们,但是它们没有依赖你。通常你只要安装相应的@types就可以,例如lodash模块:

npm install --save-dev @types/lodash

这些typings帮助type在你的代码中流动,同时让你的错误浮现。

如果你的代码调用了额外的APIs,你也应该给它们添加types,因为你依赖了它们,但是它们没有依赖你。添加依赖的方法见技巧35。

迁移你自己的模块的时候,用某些工具对你的依赖图进行可视化非常有用。例如,madge工具。

image.png

当你将js换成ts过程中,你会遇到一些常见的错误:

未声明的class 属性

class在js中不需要声明它的属性,但是ts中的class需要。当你将.js后缀改为.ts后缀,会报这样的错:

class Greeting {
  constructor(name) {
    this.greeting = 'Hello';
      // ~~~~~~~~ Property 'greeting' does not exist on type 'Greeting'
    this.name = name;
      // ~~~~ Property 'name' does not exist on type 'Greeting'
  }
  greet() {
    return this.greeting + ' ' + this.name;
             // ~~~~~~~~              ~~~~ Property ... does not exist
  }
}

当然有一个快速修复的方法,你可以使用:

image.png 这会根据使用添加属性:

class Greeting {
  greeting: string;
  name: any;
  constructor(name) {
    this.greeting = 'Hello';
    this.name = name;
  }
  greet() {
    return this.greeting + ' ' + this.name;
  }
}

ts正确添加了greeting的type,但是错误添加了name的type。在快速修复后,你需要检查一遍属性列表,对不正确的type的进行修复。

改变types的values

ts可能会这样报错:

const state = {};
state.name = 'New York';
   // ~~~~ Property 'name' does not exist on type '{}'
state.capital = 'Albany';
   // ~~~~~~~ Property 'capital' does not exist on type '{}'

这个错误在技巧23讲解的更深入。如果你遇到这个错误,可以对state进行显性类型声明:

const state = {
  name: 'New York',
  capital: 'Albany',
};  // OK

如果你的state不是这个type,你还可以这样做:

interface State {
  name: string;
  capital: string;
}
const state = {} as State;
state.name = 'New York';  // OK
state.capital = 'Albany';  // OK

如果你是用JSDoc和@ts-check,你需要意识到:当你让js转成ts可能会丢失类型安全。 例如@ts-check可能会这样报错:

/ @ts-check
/**
 * @param {number} num
 */
function double(num) {
  return 2 * num;
}

double('trouble');
    // ~~~~~~~~~ Argument of type '"trouble"' is not assignable to
    //           parameter of type 'number'

当你转成ts后,@ts-check会自动停止,上面有意义的报错会停止:

/**
 * @param {number} num
 */
function double(num) {
  return 2 * num;
}
double('trouble');  // OK

幸运的是这类错误也有快速修复:

image.png 一但你添加了type,记得把JSDoc及时删除。

最后迁移你的test,它们应该在你的依赖图的上方。这非常重要:在迁移的过程中能通过测试。