返回函数的通用 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>

然后泛型类型应该替换fetchUserReturnType与返回函数的ReturnType。像这样:

type dispatchedAction = GuruMagic<typeof fetchUser>;
// so that dispatchedAction === (id: Id) => Promise<boolean>

我知道我可以申请ReturnType两次得到Promise&lt;boolean&gt;,但是我不知道如何将原始参数(可能是多个)与这个返回类型连接起来。 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,然后从参数列表中返回一个新函数AR。有用吗?

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&lt;T&gt; 类型的函数,除非您以某种方式提供缺少的参数,否则您将遇到问题。但也许你甚至没有在给定T 的情况下实现GuruMagic&lt;T&gt;。无论如何,这是你的事,不是我的。

无论如何,希望对您有所帮助。祝你好运!

【讨论】:

感谢您的精彩回答!完美运行!我只会将它用于 redux-thunk-actions。我忽略了中间参数,但在调度操作时由 redux 本身使用。当您将对象作为mapDispatchToProps 参数传递时,如我的动机代码块的最后一行所示,redux 基本上将其转换为 fetchUser: (...args) =&gt; dispatch(fetchUser(...args)) 。因此,您的 GuruMagic 类型让我可以推断出 this 的结果类型,以便更轻松地键入我的组件道具。再次感谢! :) PS:我可能会调整你的定义,只允许ThunkActions 完美答案!不过我很好奇,有没有办法修改它以使用函数对象? @PeterKottas “函数对象”是什么意思?所需的输入和输出类型是什么?可能您只想使用mapped type。如果您的问题更复杂,或者您需要的帮助比您自己的问题要多。 @jcalz 与此处提到的示例完全相同,我只有值是函数的对象。我想在那个对象上使用这个 GuruMagic 而不是单个函数。这个想法是它会为您提供该对象的类型,从而减少该对象中所有函数的复制粘贴代码。 (你也可能忘记映射一个函数) 实际上这可能有效(afk)type GuruObjectMagic&lt;T&gt; = [P in keyof T]?: GuruMagic&lt;typeof T[P]&gt;;

以上是关于返回函数的通用 TypeScript 类型,将 ReturnType 替换为返回函数的 ReturnType的主要内容,如果未能解决你的问题,请参考以下文章

具有通用联合约束的 TypeScript 函数返回值

基于可选函数参数的不同返回类型 - Typescript

TypeScript 通用函数 - 为数组应用函数时出现“参数不可分配错误”

映射具有未知深度的通用 TypeScript 接口

TypeScript 类型推断 - 函数的通用对象

Typescript - 如果我想返回对象,函数返回类型