目录
作为一种编程语言,JavaScript 依赖于第一类函数的概念,这意味着函数被视为任何其他变量,如数字、字符串或阵列。这样做的好处之一是,函数可以被传递到其他函数中,从函数中返回,或者分配给变量,以便以后需要时调用。
这个功能在异步代码中被大量使用,函数经常被传入异步函数,通常被称为回调。但当我们利用TypeScript时,这可能是很棘手的。
TypeScript为我们提供了增加静态类型和转译检查的奇妙好处,它可以帮助我们更好地记录我们期望进入函数的变量类型--但如果我们需要传递函数会怎样?
当然,我们需要为这些函数打字,这一点似乎相当清楚,但我们如何为它们打字,以及如何在TypeScript中传递函数?
在本教程中,你将了解TypeScript函数以及如何在你的应用程序中把它们作为参数传递。
什么是TypeScript函数类型?
简单变量的类型可能是大多数TypeScript开发人员熟悉的东西。但为一个函数构建一个类型就比较困难了。
一个函数类型(注意:这个链接重定向到旧的TypeScript文档,但它有一个比新的文档更清晰的例子)是由函数接受的参数类型和函数的返回类型组成的。
我们可以用一个非常简单的例子来说明这一点。
const stringify = (el : any) : string => { return el + "" }
const numberify = (el : any) : number => { return Number(el) }
let test = stringify;
test = numberify;
上面的例子,如果在JavaScript中实现,可以正常工作,没有任何问题。
但是现在我们利用了TypeScript,当我们试图转译我们的代码时就会出现错误。
- Type '(el: any) => number' is not assignable to type '(el: any) => string'.
- Type 'number' is not assignable to type 'string'.
这里抛出的错误信息很有描述性:stringify 和numberify 函数是不能互换的。
它们不能互换地分配给test 变量,因为它们的类型有冲突。它们收到的参数是相同的(一个参数的类型是any ),但由于它们的返回类型不同,我们收到了错误。
我们可以改变这里的返回类型来证明我们的理论是正确的。
const stringify = (el : any) : number => { return 1 }
const numberify = (el : any) : number => { return Number(el) }
let test = stringify;
test = numberify;
上面的代码现在如期工作了,唯一的区别是我们改变了stringify 函数的类型,使其与numberify 函数的类型一致。事实上,返回类型正在破坏这个例子。
在TypeScript中使用参数编号
有趣的是,许多其他语言不仅会根据参数类型和返回类型来创建这些函数类型,还会根据函数的参数数量来创建。
让我们做一个最后的例子来扩展我们最后的工作例子。
const stringify = (el : any, el2: number) : number => { return 1 }
const numberify = (el : any) : number => { return Number(el) }
let test = stringify;
test = numberify;
熟悉其他语言的开发者可能会认为上面的函数例子不能互换,因为它通常被称为函数重载。
不过这个例子没有抛出错误,而且在TypeScript中完全合法,因为TypeScript实现了所谓的鸭子类型化。
这只是一个小提示,但重要的是要记住:在TypeScript中,参数的数量并没有被用于函数的类型定义中。
在TypeScript中对我们的函数进行类型化示例
现在我们确切地知道如何为我们的函数构建类型。我们只需要确保我们在TypeScript中传递的函数的类型。
让我们再次一起完成一个失败的例子。
const parentFunction = (el : () ) : number => { return el() }
上面的例子没有成功,但它抓住了我们需要的东西。
我们需要把它传递给一个父函数一个回调,它可以在以后被调用。那么,我们在这里需要改变什么呢?
- 我们需要键入
el函数参数 - 我们需要键入我们传入
el函数的参数(如果它需要这些参数的话)
这样做后,我们的例子现在应该是这样的。
const parentFunction = (el : () => any ) : number => { return el() }
这个具体的例子不需要参数,但如果需要的话,它将是这样的。
const parentFunction = (el : (arg: string) => any ) : number => { return el("Hello :)") }
这个例子相对简单,以方便解释TypeScript函数的概念,但如果你有更复杂的类型,你可能会花大量的时间来输入一切。
社区维护了大量TypeScript中常用的高质量开源类型,称为DefinitelyTyped,它可以帮助你简化和加快你需要利用的类型。
总结
我希望这篇文章是有用的,这样你就能更好地理解围绕着将函数作为参数传递给其他函数的TypeScript情况。
回调通常依赖于这种方法,所以你会经常看到在任何成熟的TypeScript代码库中大量使用回调。编码愉快!