Skip to content

Item 82: Convert Module by Module Up Your Dependency Graph

要点

  • Start migration by adding @types for third-party modules and external API calls.
  • Begin migrating your own modules from the bottom of the dependency graph upwards. The first module will usually be some sort of utility code. Consider visualizing the dependency graph to help you track progress.
  • Resist the urge to refactor your code as you uncover odd designs. Keep a list of ideas for future refactors, but stay focused on TypeScript conversion.
  • Be aware of common errors that come up during conversion. Move JSDoc types into TypeScript type annotations if necessary to avoid losing type safety as you convert.
  • 通过为第三方模块和外部 API 调用添加 @types 来开始迁移。
  • 从依赖图底部开始迁移你自己的模块,逐步向上迁移。第一个模块通常是某种实用工具代码。考虑可视化依赖图来帮助你跟踪进度。
  • 抵制在发现奇怪设计时重构代码的冲动。保持一个未来重构的想法列表,但要专注于 TypeScript 的转换。
  • 注意转换过程中常见的错误。必要时将 JSDoc 类型转换为 TypeScript 类型注解,以避免在转换过程中丢失类型安全。

正文

ts
async function fetchTable() {
  const response = await fetch('/data')
  if (!response.ok) throw new Error('Failed to fetch!')
  return response.json()
}

💻 playground


ts
interface TabularData {
  columns: string[]
  rows: number[][]
}
async function fetchTable(): Promise<TabularData> {
  const response = await fetch('/data')
  if (!response.ok) throw new Error('Failed to fetch!')
  return response.json()
}

💻 playground


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
  }
}

💻 playground


ts
class Greeting {
  greeting: string
  name: any
  constructor(name) {
    this.greeting = 'Hello'
    this.name = name
  }
  greet() {
    return `${this.greeting} ${this.name}`
  }
}

💻 playground


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

💻 playground


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

💻 playground


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

💻 playground


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

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

💻 playground


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

double('trouble') // OK

💻 playground


ts
function double(num: number) {
  return 2 * num
}

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

💻 playground

Released under the MIT License.