Generic TypeScript Type for functions returning functions that replaces the ReturnType with the ReturnType of the returned function

我与影子孤独终老i 提交于 2019-12-12 01:03:29

问题


Dear TypeScript-3-Gurus out there,

can someone help my define a generic type GuruMagic<T> that does the following?

T is a function returning a function, e.g. this:

fetchUser(id: Id) => (dispatch: Dispatch) => Promise<boolean>

The generic type should then replace the ReturnTypeof fetchUserwith the ReturnTypeof the returned function. Like this:

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

I know that I can apply ReturnType two times to get Promise<boolean>, but I don't know how to concat the original parameters (possibly multiple) with this return type. Is this even possible with TypeScript (3.x)?

Other examples for clarity

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

Motivation

Typesafe Redux-Thunk. When I connect a react component it would be great if I could just do this:

import { fetchUser } from './myActions';

interface IPropsOfMyComponent {
  fetchUser: GuruMagic<typeof fetchUser>;
}

// ... MyComponent Definition ...

connect<{}, IPropsOfMyComponent, {}>(null, { fetchUser })(MyComponent)

回答1:


Yes, you can do this with conditional types and the generic argument-list manipulation powers introduced in TypeScript 3.0 via support for tuple types in rest and spread expressions. Here's one way to do it:

type GuruMagic<FF extends (...args: any[]) => (...args: any[]) => any> =
  FF extends (...args: infer A) => (...args: infer _) => infer R ? (...args: A) => R 
  : never;

So you infer the argument list for the function FF as A, and the return type of the return type of the function FF as R, and then return a new function from an argument list of A to R. Does it work?

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

Yes it does!

I'm not 100% sure how you will use this type function in practice... the fact that it ignores the type of the arguments of the intermediate function worries me. If you try to actually implement a function of type GuruMagic<T> given a function of type T you will have a problem unless you supply the missing arguments somehow. But maybe you're not even implementing a GuruMagic<T> given a T. Anyway, that's your business, not mine.

Anyway, hope that helps. Good luck!



来源:https://stackoverflow.com/questions/52184025/generic-typescript-type-for-functions-returning-functions-that-replaces-the-retu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!