web-dev-qa-db-fra.com

Dans TypeScript, définissez un type pour un tableau où le premier élément est plus spécifique que le reste

Je voudrais définir un type pour un tableau dont le premier élément est un type spécifique (par exemple Function), et les éléments restants sont le type vide. Par exemple:

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

Une telle chose est possible?

Le but est de fournir une fonction à argument unique comme celle-ci:

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

Une approche alternative serait d'utiliser deux arguments pour myCaller, comme ceci:

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

mais pour des raisons esthétiques, je préférerais utiliser un seul argument. Je me demande également si le système de type prend en charge ce qui est sans doute un tuple de longueur arbitraire. Peut-être qu'une telle chose n'est pas souhaitable pour des raisons informatiques que je ne comprends pas.

24
anticrisis

Si vous définissez

type FAs = [Function, {}];

Les valeurs de type FAs nécessiteront alors un premier élément de type Function, un deuxième élément de type {}, et les éléments suivants de Function | {}. C'est ainsi que fonctionnent les types de tableaux littéraux TypeScript. À partir de TS docs :

Lors de l'accès à un élément en dehors de l'ensemble des indices connus, un type d'union est utilisé à la place:

Cela devrait faire tout ce que vous voulez sauf pour le fait que vous pourrez passer une valeur typée Function- comme troisième élément etc. du tableau. Mais en fait, ce serait le cas de toute façon, puisque Function est compatible avec {}.

Il n'y a aucun moyen de contourner cela. Il n'y a aucun moyen dans TS de définir un type de tableau où les premiers éléments n sont de certains types spécifiques, et il existe un nombre arbitraire d'éléments restants d'un autre type spécifique.

Je me demande également si le système de type prend en charge ce qui est sans doute un tuple de longueur arbitraire.

En fait, le système de type uniquement prend en charge les tuples de longueur arbitraire. Si tu le dis

type Tuple = [number, number];

ce type est compatible avec n'importe quel tableau de longueur deux ou plus , qui contient des nombres. Si tu le dis

type Tuple = [string, number];

ce type est compatible avec n'importe quel tableau, de longueur deux ou plus , qui a une chaîne comme premier élément, un nombre comme deuxième, et soit un chaîne ou nombre comme troisième etc. Je n'appellerais pas les raisons de ce comportement "basées sur l'informatique"; c'est plus une question de ce qu'il est possible pour TS de vérifier.

Une approche alternative

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];
17
user663031

Dans les versions actuelles de TypeScript, cela est possible en utilisant la propagation de tableau:

type FAs = [Function, ...Array<{}>]

Il prend en charge n'importe quelle longueur de 1 à n (le premier élément est requis).

21
juusaw

Je suis presque sûr que c'est le meilleur que vous puissiez faire avec TypeScript 2.3. Vous pouvez voir des saisies comme celle-ci dans lodash par exemple.

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
dbandstra