In Typescript, define a type for an array where the first element is more specific than the rest

I would like to define a type for an array whose first element is a specific type (e.g. Function) and the rest of the elements are an empty type. For example:

type FAs = [Function, {}, {}, {}, ...]; // pseudo code 

Is it possible?

The goal is to provide a function with one argument as follows:

 const myCaller = ([fun, ...args]: FAs) => fun.apply(args); 

An alternative approach would be to use two arguments for myCaller , for example:

 const myCaller = (fun: Function, args: any[]) => fun.apply(args); 

but for aesthetic reasons, I would prefer to use one argument. I also wonder if the type system supports what is possibly a tuple of arbitrary length. Maybe such a thing is undesirable for computer science, why I do not understand.

+7
types typescript
source share
2 answers

If you define

 type FAs = [Function, {}]; 

Then values โ€‹โ€‹of type FAs will need the first element of type Function , the second element of type {} and the subsequent elements of Function | {} Function | {} . This is how literal types like TypeScript work. From TS docs :

When accessing an element outside the set of known indexes, the union type is used instead:

This should do everything you need except because you can pass the Function value as the third element, etc. array. But actually it would be anyway, since Function compatible with {} .

There is no way around this. In TS, there is no way to determine the type of array, where the first n elements have a specific type (s), and there is an arbitrary number of remaining elements of another specific type.

I am also wondering if the type system supports what is possibly a tuple of arbitrary length.

In fact, the type system only supports tuples of arbitrary length. If you say

 type Tuple = [number, number]; 

this type is compatible with any array of length 2 or more that contains numbers. If you say

 type Tuple = [string, number]; 

this type is compatible with any array of length 2 or longer that has a row as its first element, a second number and a row or number as its third, etc. I would not call the reasons for this behavior "computer-based"; it is more a question of what TS can be checked.

Alternative approach

 interface Arglist { [index: number]: object; 0: Function; } const a1: Arglist = [func]; const a2: Arglist = [22]; // fails const a3: Arglist = [func, "foo"]; // fails const a4: Arglist = [func, obj]; const a5: Arglist = [func, obj, obj]; 
+6
source share

I am sure this is the best you can do with Typescript 2.3. For example, in lodash you can see typing.

 interface IMyCaller { <R>([fn]: [() => R]): R; <R,A>([fn, a]: [(a: A) => R, A]): R; <R,A,B>([fn, a, b]: [(a: A, b: B) => R, A, B]): R; <R,A,B,C>([fn, a, b, c]: [(a: A, b: B, c: C) => R, A, B, C]): R; // keep adding these until you get tired } const myCaller: IMyCaller = ([fun, ...args]) => fun.apply(args); 
0
source share

All Articles