-
不应该使用
Function
作为类型。它表示任何函数。 -
通常,您希望更具体-例如指定参数的数量或函数返回的内容。
-
如果您确实希望表示一个可以接受任意数量的参数并返回任何类型的函数,请使用
(...args: any[]) => any
。
完整的解释
让我们想象一下,你正在创建一个函数,它汇总了一个对象数组。这里有一个例子,取自excaldraw代码库:
const sum = <T>(
array: readonly T[],
mapper: (item: T) => number
): number =>
array.reduce(
(acc, item) => acc+ mapper(item),
0
);
让我们看一下类型定义。这个函数接受:
-
readonly T[]
-
映射函数:
(item: T) => number
返回 number
。
在代码体中,它调用array.reduce(func, 0)
。这意味着函数中的 acc
从 0
开始。
对于数组的每个成员,它将 acc
和 mapper(item)
加在一起。最后得到的是数组中所有元素的和。
函数声明做了什么?
mapper
函数是关键。让我们把它剥开来看一看:
type Mapper<T> = (item: T) => number;
让我们想象一下这个用例:
interface YouTubeVideo {
name: string;
views: number;
}
const youTubeVideos: YouTubeVideo[] = [
{
name: "My favorite cheese",
views: 100,
},
{
name: "My second favorite cheese (you won't believe it)",
views: 67,
},
];
const mapper: Mapper<YouTubeVideo> = (video) => {
return video.views;
};
const result = sum(youTubeVideos,mapper); // 167
这里, mapper
表示从对象中提取数字的函数。 sum
函数的强大之处在于,你可以放弃大多数类型声明:
const youTubeVideos = [
{name: "My favorite cheese",views: 100 },
{
name: "My second favorite cheese (you won't believe it)",
views: 67,
},
];
const result = sum(youTubeVideos, (video) => {
return video.views;
}); // 167
实际上我们已经丢弃了所有的类型声明,但是 video
仍然被推断为 { name: string; views: number }
。这是可能的,因为函数定义的特殊性: (item: T) => number
。
Function
呢?
我看到很多新手开发者犯的一个大错误是用 Function
类型声明像 mapper
这样的函数:
const sum = <T>(
array: readonly T[],
mapper: Function
): number =>
array.reduce(
(acc, item) => acc+ mapper(item),
0
);
这个关键字基本上代表“任何函数”。这意味着 sum
在技术上可以接收任何函数。
当在 sum
中使用时,我们失去了 (item: T) => number
提供的很多安全性:
TypeScript现在不能推断出 item
应该是什么,或者我们的mapper函数应该返回什么。
这里的教训是“不要使用 Function
”——总是有更具体的选项可用。
选择
表示“任意函数”
有时候,你会想要在TypeScript中表达“任意函数”。为此,让我们来看看TypeScript的一些内置类型,Parameters
和 ReturnType
。
export type Parameters<
T extends (...args: any) => any
> = T extends (...args: infer P) => any
? P
: never;
export type ReturnType<
T extends (...args: any) => any
> = T extends (...args: any) => infer R ? R : any;
您将注意到这两个实用程序类型使用相同的约束: (...args: any) => any
。
(...args: any)
表示函数可以接受任意数量的实参, => any
表示它可以返回任何值。
表示不带参数的函数
要表达一个没有参数的函数(但会返回任何值),你需要使用 () => any
:
总结
在表示类型时不应该使用Function
。
(a: string, b: number) => any
语法可用于只指定参数而不指定返回类型的情况。
(...args: any) => any 可以用来表示任何函数类型。
欢迎关注公众号:文本魔术,了解更多