使用 TypeScript 开发你的项目

3,125 阅读4分钟

关于 TypeScript

早在去年(2017),TypeScript 赢来了它的爆发式增长。时至今日,随着 JavaScript 的代码数量越来越庞大,越来越多的开发者意识到 JavaScript 在构建大型项目时的不足之处。JavaScript 是动态类型的,只能在 runtime 时进行类型检查;同时它也给重构大型项目带来了的困扰,在一定程度上,它是不「易读」的。而 TypeScript 能够很好的解决上述问题。

TypeScript 下载量

TypeScript 最早是在 2012 年十月份由微软开源在 GitHub 上,它是 JavaScript 的一个超集,除了能让我们使用 ES Future 的各种语法外,还提供如 Enum、Tuple、Generics 等的新语法。当然,向 JavaScript 提供一个可选的静态类型是一个最重要的变化点了。

在接下来,我将简单的阐述为什么静态类型对大型项目是友好的,以及对 Function type 的一次实践写法。

静态类型对大型项目是友好的

尽早检查错误

如前文所提及的,JavaScript 是动态类型的语言,它没有 Type System,只能在 runtime 时进行类型检查,如果你不是足够的小心,难免会出现下列情况:

在这个简单的例子里,我们认为 someMethod 的参数一个数组,可是实际情况并不是,它是一个数字。理所当然,它报错了。

改为 TypeScript 加上简单的类型推断时:

可见,它在编译前就已经给出了错误的提示。

阅读代码友好

或许你也刚好认为「代码是给人读的,只是顺便在机器上跑一下」,我相信你会在 Function、Class、Modules 或者其他地方加上 JSDoc。不同于 JSDoc,TypeScript 提供的类型声明和模块接口形成了文档的形状,提供程序的行为提示,并在编译时会校验程序的正确性。

改动下上个例子:

当然,对大型项目来说,这可能要复杂的多。尽早的发现错误,对阅读代码更友好,或多或少能让我们在重构项目时更方便。

Function type

先从一个简单的 Function type 入手:

(arg: number) => string

在上面的一个 Function type 中,它接收一个数字类型的参数,并返回一个字符串类型。

现在来使用它:

const func: (arg: number) => string = String // 在这里 String 是一个方法

在实际应用中,并不会这么用,因为 TypeScript 知道 String 的类型,并能准确的推导出 func 的类型。

一个更加实际的例子:

function someMethods (callback: (arg: number) => string) {
  return callback(321)
}

现在,你可以使用这个定义的方法,但是传入的参数必须符合 (arg: number) => string,比如你可以使用 someMethods(String) 而不能使用 someMethods(Number)

加上函数返回:

function someMethod (
  callback: (num: number) => string
): string {
  const num = 123
  return String(num)
}

有些时候,并不想传 callback

function someMethod (
  callback?: (num: number) => string
): string {
  const num = 123
  if (callback) {
    return callback(123)
  }
  return String(num)
}

或者,我们希望 callback 是必须的,如果你不想提供一个函数,你必须显式的提供一个 null:

function someMethod (
  callback: null | ((num: number) => string)
): string {
  const num = 123
  if (callback) {
    return callback(123)
  }
  return String(num)
}

定义成一个 type:

type SomeMethod = (callback?: ((num: number) => string)) => string

在这个 type 里,我们定义了一个 someMethod 方法,它有一个可选参数 callback,同时规定这个 callback 有且仅有一个类型为 number 的参数。

接下来,我们扩展这个 type ,使用泛型(你可以简单的理解泛型是一种数据类型)并改变它的 callback:

type SomeMethod<T> = (
  callback: (value: T, index: number, array: T[]) => T
) => T

给泛型加一个默认值,并加个可选参数:

type SomeMethod<T = string> = (
  callback: (value: T, index: number, array: T[]) => T,
  thisArg?: T
) => T

至此,一个简单的 Function type 已经完成了。

事实上,Function types 还有各种有趣玩法:

type SomeMethod<T = string> = (
  callback: (...arg: (T[] | T)[]) => T[]
  // ...
) => T
// 多泛型,并带有约束时
type OthemMethod <T, P extends keyof T> = (
  obj: T,
  key: P
) => T[P]

实际上 TypeScript 2.4 版本以后,可以对函数调用的返回值进行判断

function arrayMap<T, U>(
  f: (x: T) => U
): (a: T[]) => U[] {
  return a => a.map(f)
}

const lengths: (a: string[]) => number[] = arrayMap(a => a.length)

console.log(lengths(['123', '1', '1'])) // 3, 1, 1

以及更多有趣的写法,这里不再介绍了。


参考:

  • https://www.typescriptlang.org/docs/home.html
  • https://zhuanlan.zhihu.com/p/24267683
  • https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html
  • https://juejin.cn/post/6844903497205448711