zcaudate
zcaudate

Reputation: 14258

is there a way to generalise the number of arguments in a function type?

I have an alias for a function type definition:

IFn_1 = (_: any) => any

What I'd like to do is to generalise this into something like this:

IFn<n, out>

How would the template be defined where n is the number of arguments and out is the output type. The original definition then becomes:

IFn<1, any>

Upvotes: 0

Views: 39

Answers (1)

jcalz
jcalz

Reputation: 328132

If there were an easy way to generate a tuple given its desired length as a numeric literal type, then this would be an easy question to answer. Unfortunately, while this has been suggested, it's not part of the language yet.

Realistically the best we can do (without support for recursive conditional types) is to make our own type alias TupleOfLength<N, V> which produces a tuple of N copies of the value type V up to a hardcoded maximum number for N. This is one way to do it:

type TupleOfLength<N extends number, V = any> = Extract<
  [
    [],
    [V],
    [V, V],
    [V, V, V],
    [V, V, V, V],
    [V, V, V, V, V],
    [V, V, V, V, V, V],
    [V, V, V, V, V, V, V],
    [V, V, V, V, V, V, V, V],
    // add more here if you need them
    ...V[][]
  ][N],
  any[]
>;

This works well when N is in the anticipated range:

type SixStrings = TupleOfLength<6, string>;
// type SixStrings = [string, string, string, string, string, string] 👍

And not so well when it's not:

type AMillionBooleans = TupleOfLength<1000000, boolean>;
// type AMillionBooleans = boolean[] oh well 😟

So let's take TupleOfLength<N, V> as a given and use it to define IFn<N, R>:

type IFn<N extends number, R = void> = (...args: TupleOfLength<N, any>) => R;

And let's see if it works:

type ThreeInStringOut = IFn<3, string>;
// type ThreeInStringOut = (args_0: any, args_1: any, args_2: any) => string

type NoneInNumberOut = IFn<0, number>;
// type NoneInNumberOut = () => number

type OneInAnyOut = IFn<1, any>;
// type OneInAnyOut = (args_0: any) => any

type GoogolInGoogolOut = IFn<1e100, 1e100>;
// type GoogolInGoogolOut = (...args: any[]) => 1e+100 o

Those all look fine, with the possible exception of when we pass a too-big number into N.

Okay, hope that helps; good luck!

Link to code

Upvotes: 2

Related Questions