嗨,我想知道可重用函数类型(相同的参数、返回类型、可由多个函数重用)和泛型的最佳语法是什么?
当时我想不出更短的语法:
type CountResult<T extends object> = (arg: T) => [T, number]
function log<T extends object>(arg: T){
console.log(arg)
}
function countWithKeys<T extends object>(arg: Parameters<CountResult<T>>[0]): ReturnType<CountResult<T>> {
const count = Object.keys(arg).length
log<T>(arg) // Need to be able to access T
return [arg, count]
}
function countWithLoop<T extends object>(arg: Parameters<CountResult<T>>[0]): ReturnType<CountResult<T>>{
let count = 0;
for(const i in arg) {
count++;
}
log<T>(arg)
return [arg, count]
}
我基本上是在问重用泛型函数的类型签名的最佳语法是什么。
您的generic类型参数的范围不正确,或者至少不利于用于您的目的。泛型函数在调用签名上具有类型参数(如
type F = <T>(t: T)=>void
),而泛型类型的参数在类型名称上(如type F<T> = (t: T)=>void
)。这些是不同的;请参阅泛型参数放置之间的打字稿差异以获取更多讨论。
您真正想要的类型是这样的:
type CountResult = <T extends object>(arg: T) => [T, number]
要为
countWithKeys
和 countWithLoop
提供该类型,您需要从使用 function
语句 更改为函数 表达式(例如 function
表达式 或 箭头功能)。
这是因为我们目前无法在 TypeScript 中直接注释函数语句。 microsoft/TypeScript#22063 有一个支持函数语句注释的开放功能请求,但不幸的是,目前它们还不是该语言的一部分。
所以让我们使用箭头函数:
const countWithKeys: CountResult = arg => {
const count = Object.keys(arg).length
log(arg);
return [arg, count]
}
const countWithLoop: CountResult = arg => {
let count = 0;
for (const i in arg) {
count++;
}
log(arg);
return [arg, count]
}
编译没有错误,并且
arg
类型参数是 contextually 给定适当的泛型类型。看起来不错,我们都完成了。
好吧,除了您显然需要在函数的实现中引用泛型类型参数
T
。您的示例是您希望能够调用 log<T>(arg)
而不是 log(arg)
。这绝对没有必要,因为编译器会很乐意为您推断类型参数。但为了继续下去,让我们假装log(arg)
不起作用,而你确实需要log<T>(arg)
。想必在真实的代码中有一个更有说服力的用例。
无论如何,在上面的函数实现中,你想要的类型参数是anonymous,你不能直接使用它。为了解决这个问题,您需要以某种方式给该类型一个名称。最直接但冗长的方法是显式且完整地注释实现,包括相关的类型参数声明:
const countWithKeys: CountResult = <T extends object>(arg: T) => {
const count = Object.keys(arg).length
log<T>(arg);
return [arg, count]
}
另一种方法是尝试以其他方式获取对匿名类型的引用。对于
CountResult
,arg
参数属于相关类型,因此您可以使用 typeof
类型运算符:
const countWithLoop: CountResult = arg => {
type T = typeof arg;
let count = 0;
for (const i in arg) {
count++;
}
log<T>(arg);
return [arg, count]
}
这有点不那么冗长,但更难概括并且可能更令人困惑。
这里没有“完美”的方法;您要么需要让编译器为您推断事物,从而使它们匿名,要么需要显式指定和注释这些事物,从而使它们可能是多余的。这已经是最好的了。