简体   繁体   中英

How to correctly type Parameters of generic function?

I'm trying to assign a function's parameters to a type alias. Eg for this function:

function foo<T>(bar: T, baz: number) {}

I want to get the signature of its parameters. Ordinarily, I'd do this:

type FooParams = Parameters<typeof foo>;

but the problem is that that results in a signature of [{}, number] which makes sense because I haven't specified what T is. However, then I'd expect this to work:

type FooParams<T> = Parameters<typeof foo<T>>; // hopefully [T, number]

but it doesn't, it just results in a bunch of syntax errors.

Is it possible to correctly get the type of a generic function's parameters list?

You can use for that infer keyword:

type Args<T> = T extends (...args: infer I) => any ? I : never;

type R = Args<(args: number, arg: string) => number >;
// R = [number, string] 

It means that type I is treat as treat as generic, but you don't have to declare it like: let fn = <T>(arg:T): T {...

playground , docs


You can achieve generic types but you have to declare type of function:

type Foo<T> = (bar: T, baz: number) => void;
type R2<Placeholder> = Args<Foo<Placeholder>>; // [Placeholder, number]
type R3 = R2<boolean> // [boolean, number]

My solution is only a workaround which might help. This is not exactly what you want

Here you have non generic solution.I mean it works only with foo type signature

function foo<T>(bar: T, baz: number) { }

type Fn = (...args: any) => any
type Tail<T extends any[]> = T extends [infer _, ...infer Rest] ? Rest : never

type ReplaceFirstParameter<F extends Fn, Fst> =
    (fst: Fst, ...args: Tail<Parameters<F>>) => ReturnType<F>

type Foo<T> = ReplaceFirstParameter<typeof foo, T>

type Result = ReplaceFirstParameter<typeof foo, number> // (fst: number, baz: number) => void

This solution is most more generic. It will replace all unknown params with provided generic argument.

I assume that every function generic is unknown - this is the weak place.

type MapPredicate<T, V> = T extends unknown ? V : T

type ReplaceUnknown<
    Arr extends Array<unknown>,
    Value,
    Result extends Array<unknown> = []
    > = Arr extends []
    ? []
    : Arr extends [infer H]
    ? [...Result, MapPredicate<H, Value>]
    : Arr extends [infer Head, ...infer Tail]
    ? ReplaceUnknown<[...Tail], Value, [...Result, MapPredicate<Head, Value>]>
    : Readonly<Result>;

function foo<T>(bar: T, baz: number) { }

type Fn = (...args: any) => any

type ReplaceParameters<F extends Fn, Value> =
    (...args: ReplaceUnknown<Parameters<F>, Value>) => ReturnType<F>


type Result = ReplaceParameters<typeof foo, number> // (fst: number, baz: number) => void

Playground

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM