问题
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 ReturnType
of fetchUser
with the ReturnType
of 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