TypeScript:函数作为参数与严格类型化——完整解析与示例
\n\n你好,同行!如果你曾经用 JavaScript 编写过代码,并将一个函数传递给另一个函数(例如,传递给 setTimeout 或 Array.map),那么你已经熟悉了高阶函数的概念。但当涉及到 TypeScript 时,一个合乎逻辑的问题出现了:"我能否对我作为参数传递的函数进行严格类型化?"。答案是肯定的,并且这是该语言最强大的特性之一。
在本文中,我们将探讨如何声明TypeScript 中的函数类型,如何将它们作为参数传递,以及如何避免在签名上出错。你将了解如何使代码不仅安全,而且具有自文档性。我们开始吧!
\n\n顺便提一下,这个问题是 Stack Overflow 上最热门的问题之一(有数千次浏览)。所以,如果你想一劳永逸地弄明白——你来对地方了。
\n\n为什么这很重要:严格类型化节省时间
\n\n想象一下,你正在编写一个接受另一个函数(回调)的函数。没有类型,你可能会意外地传递一个参数数量错误或返回值类型错误的函数。TypeScript 在编译阶段就能捕获这些错误,而不是在运行时。这就像给你的代码上了一道保险。
\n\n下面是一个没有类型就无法工作的例子:
\n\n// JavaScript(无类型)——错误只会在运行时出现\nfunction processData(callback) {\n const result = callback(10, 20);\n console.log(result);\n}\n\n// 哎呀,传递了一个只有一个参数的函数\nprocessData((x) => x * 2); // NaN —— 因为第二个参数是 undefined\n\n使用 TypeScript,我们可以明确指定回调期望的签名:
\n\n// TypeScript —— 编译阶段报错\nfunction processData(callback: (a: number, b: number) => number): void {\n const result = callback(10, 20);\n console.log(result);\n}\n\n// ✅ 正确\nprocessData((x, y) => x + y); // 30\n\n// ❌ 错误:类型 '(x: number) => number' 不能赋值给类型 '(a: number, b: number) => number'\n// processData((x) => x * 2);\n\n很酷,对吧?现在让我们来分解所有声明此类类型的方法。
\n\n方法 1:内联签名(最简单)
\n\n最直接的方法是在参数中直接指定函数签名。当函数参数只使用一次时,这很方便。
\n\n// 一个接受另一个函数(两个数字并返回字符串)的函数\nfunction formatNumbers(\n a: number,\n b: number,\n formatter: (x: number, y: number) => string\n): string {\n return formatter(a, b);\n}\n\n// 使用\nconst result = formatNumbers(5, 10, (x, y) => `总和:${x + y}`);\nconsole.log(result); // "总和:15"\n\n优点:快速、直观。
\n缺点:如果签名重复,将不得不复制代码。
方法 2:函数的类型别名(可复用)
\n\n如果你在多个地方使用相同的签名,最好将其提取到类型别名中。这使代码更简洁且更易于维护。
\n\n// 声明函数类型\ntype Callback = (error: Error | null, data: string) => void;\n\n// 接受 Callback 的函数\nfunction fetchData(url: string, callback: Callback): void {\n // 模拟异步请求\n setTimeout(() => {\n if (url) {\n callback(null, "数据已获取");\n } else {\n callback(new Error("URL 为空"), "");\n }\n }, 1000);\n}\n\n// 使用\nfetchData("/api/data", (err, data) => {\n if (err) {\n console.error("错误:", err.message);\n } else {\n console.log("成功:", data);\n }\n});\n\n请注意:我们使用了 void 作为返回类型。这意味着该函数可以不返回任何值