返回函数的通用 TypeScript 类型,将 ReturnType 替换为返回函数的 ReturnType
Posted
技术标签:
【中文标题】返回函数的通用 TypeScript 类型,将 ReturnType 替换为返回函数的 ReturnType【英文标题】:Generic TypeScript Type for functions returning functions that replaces the ReturnType with the ReturnType of the returned function 【发布时间】:2019-02-10 12:48:55 【问题描述】:亲爱的 TypeScript-3-Gurus,
有人可以帮我定义一个泛型类型GuruMagic<T>
吗?
T
是一个返回函数的函数,例如这个:
fetchUser(id: Id) => (dispatch: Dispatch) => Promise<boolean>
然后泛型类型应该替换fetchUser
的ReturnType
与返回函数的ReturnType
。像这样:
type dispatchedAction = GuruMagic<typeof fetchUser>;
// so that dispatchedAction === (id: Id) => Promise<boolean>
我知道我可以申请ReturnType
两次得到Promise<boolean>
,但是我不知道如何将原始参数(可能是多个)与这个返回类型连接起来。 TypeScript (3.x) 甚至可以做到这一点吗?
为清楚起见的其他示例
const f1 = (a: number, b: string) => () => a;
type guruF1 = GuruMagic<typeof f1>; // (a: number, b: string) => number
const f2 = () => (name: string) => (otherName: string) => name + otherName;
type guruF2 = GuruMagic<typeof f2>; // () => (otherName: string) => string
动机
类型安全Redux-Thunk
。当我 connect
一个 react
组件时,如果我能这样做会很棒:
import fetchUser from './myActions';
interface IPropsOfMyComponent
fetchUser: GuruMagic<typeof fetchUser>;
// ... MyComponent Definition ...
connect<, IPropsOfMyComponent, >(null, fetchUser )(MyComponent)
【问题讨论】:
【参考方案1】:是的,您可以使用 conditional types 和 TypeScript 3.0 中通过支持 tuple types in rest and spread expressions 引入的通用参数列表操作功能来做到这一点。这是一种方法:
type GuruMagic<FF extends (...args: any[]) => (...args: any[]) => any> =
FF extends (...args: infer A) => (...args: infer _) => infer R ? (...args: A) => R
: never;
所以你推断函数FF
的参数列表为A
,函数FF
的返回类型的返回类型为R
,然后从参数列表中返回一个新函数A
到 R
。有用吗?
declare function fetchUser(id: Id): (dispatch: Dispatch) => Promise<boolean>
type dispatchedAction = GuruMagic<typeof fetchUser>;
// (id: Id) => Promise<boolean>
const f1 = (a: number, b: string) => () => a;
type guruF1 = GuruMagic<typeof f1>;
// (a: number, b: string) => number
const f2 = () => (name: string) => (otherName: string) => name + otherName;
type guruF2 = GuruMagic<typeof f2>;
// () => (otherName: string) => string
是的!
我不能 100% 确定您将如何在实践中使用此类型函数……事实上它忽略了中间函数的参数类型,这让我很担心。如果您尝试在给定T
类型的函数的情况下实际实现GuruMagic<T>
类型的函数,除非您以某种方式提供缺少的参数,否则您将遇到问题。但也许你甚至没有在给定T
的情况下实现GuruMagic<T>
。无论如何,这是你的事,不是我的。
无论如何,希望对您有所帮助。祝你好运!
【讨论】:
感谢您的精彩回答!完美运行!我只会将它用于 redux-thunk-actions。我忽略了中间参数,但在调度操作时由 redux 本身使用。当您将对象作为mapDispatchToProps
参数传递时,如我的动机代码块的最后一行所示,redux 基本上将其转换为 fetchUser: (...args) => dispatch(fetchUser(...args))
。因此,您的 GuruMagic
类型让我可以推断出 this 的结果类型,以便更轻松地键入我的组件道具。再次感谢! :) PS:我可能会调整你的定义,只允许ThunkActions
。
完美答案!不过我很好奇,有没有办法修改它以使用函数对象?
@PeterKottas “函数对象”是什么意思?所需的输入和输出类型是什么?可能您只想使用mapped type。如果您的问题更复杂,或者您需要的帮助比您自己的问题要多。
@jcalz 与此处提到的示例完全相同,我只有值是函数的对象。我想在那个对象上使用这个 GuruMagic 而不是单个函数。这个想法是它会为您提供该对象的类型,从而减少该对象中所有函数的复制粘贴代码。 (你也可能忘记映射一个函数)
实际上这可能有效(afk)type GuruObjectMagic<T> =
[P in keyof T]?: GuruMagic<typeof T[P]>;
以上是关于返回函数的通用 TypeScript 类型,将 ReturnType 替换为返回函数的 ReturnType的主要内容,如果未能解决你的问题,请参考以下文章