3

I'm trying to assign a function's parameters to a type alias. E.g. 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?

1
  • 6
    Nope, unfortunately there is no syntax for it at the moment. Commented Mar 15, 2019 at 11:48

2 Answers 2

1

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]
Sign up to request clarification or add additional context in comments.

3 Comments

This doesn't work for generic functions, only non-generic.
Exactly. I'm looking for something that works on generic functions.
This is a partial solution because you can't infer it directly from typeof foo but probably as good as I'm going to get for now. Thanks!
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.