将TypeScript函数作为参数传入的方法

8,546 阅读5分钟

目录

作为一种编程语言,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'.

这里抛出的错误信息很有描述性:stringifynumberify 函数是不能互换的。

它们不能互换地分配给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() } 

上面的例子没有成功,但它抓住了我们需要的东西。

我们需要把它传递给一个父函数一个回调,它可以在以后被调用。那么,我们在这里需要改变什么呢?

  1. 我们需要键入el 函数参数
  2. 我们需要键入我们传入el 函数的参数(如果它需要这些参数的话)

这样做后,我们的例子现在应该是这样的。

const parentFunction = (el : () => any ) : number => { return el() } 

这个具体的例子不需要参数,但如果需要的话,它将是这样的。

const parentFunction = (el : (arg: string) => any ) : number => { return el("Hello :)") } 

这个例子相对简单,以方便解释TypeScript函数的概念,但如果你有更复杂的类型,你可能会花大量的时间来输入一切。

社区维护了大量TypeScript中常用的高质量开源类型,称为DefinitelyTyped,它可以帮助你简化和加快你需要利用的类型。

总结

我希望这篇文章是有用的,这样你就能更好地理解围绕着将函数作为参数传递给其他函数的TypeScript情况。

回调通常依赖于这种方法,所以你会经常看到在任何成熟的TypeScript代码库中大量使用回调。编码愉快!