早在去年(2017),TypeScript 赢来了它的爆发式增长。时至今日,随着 JavaScript 的代码数量越来越庞大,越来越多的开发者意识到 JavaScript 在构建大型项目时的不足之处。JavaScript 是动态类型的,只能在 runtime 时进行类型检查;同时它也给重构大型项目带来了的困扰,在一定程度上,它是不「易读」的。而 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 入手:
(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
以及更多有趣的写法,这里不再介绍了。
参考: