2
votes

comment écrire un type `Invert` en typographie pour inverser l'ordre des tuples

type a = [1,2,3]
type Invert<T extends any[] & {'0': any}> = ???
type b = Invert<a> // should yield [3,2,1]
I am stucked to figure out the definition of Invert type of a tuple,
also an Init and Last type, although they may be constructed of each otherswhat I have tried: 
position the type in a function param definition and infer the Rest part, this approach only got the Tail part with rest params

0 commentaires

3 Réponses :


2
votes

Cela ne fonctionne que lorsque vous connaissez la longueur du tableau:

export type Prepend<Tuple extends any[], Addend> = 
     ((_: Addend, ..._1: Tuple) => any) extends ((..._: infer Result) => any) ? Result : never;
    
export type Reverse<Tuple extends any[], Prefix extends any[] = []> = {
    0: Prefix;
    1: ((..._: Tuple) => any) extends ((_: infer First, ..._1: infer Next) => any)
        ? Reverse<Next, Prepend<Prefix, First>>
        : never;
}[Tuple extends [any, ...any[]] ? 1 : 0];


type b = Reverse<[1, 2, 3]>; // type b = [3, 2, 1]

Mise à jour

En fait, il existe une solution (trouvée ici à un problème du projet dactylographié):

type a = [1,2,3]
type Invert<T extends [any, any, any]> = [T[2], T[1], T[0]];
type b = Invert<a> // should yield [3,2,1]

Lien Playground


4 commentaires

en fait, je veux obtenir une version générique


Si vous parlez d'une définition de type qui inverse un nombre quelconque d'entrées de tableau, cela n'est pas possible. Comme vous l'avez mentionné ci-dessus, cela nécessite un opérateur head and tail, qui à son tour nécessite un opérateur de repos en combinaison avec une récursivité pour les contraintes génériques. Les deux n'existent pas pour les génériques.


@Minami Mon dernier commentaire n'est pas vrai, il existe une version générique. Voir ma réponse mise à jour.


@ 1y1nq belle solution



1
votes

à partir du code dactylographié 4.0 pour approcher un type inversé est beaucoup plus facile qu'avant, en disant

type Reverse<T extends any[], R extends any[] = []> =  ReturnType<T extends [infer F, ...infer L] ? () => Reverse<L,[F,...R]> : () => R>

quelques explications:

  1. type de référence directe Reverse dans les typealias Reverse entraînera une erreur de références circulaires.
  2. wrap Reverse type in function type ( ()=> Reverse ) désactivera l'erreur de références circulaires
  3. si l'expression de type peut résoudre de manière statique, le compilateur essaiera de la résoudre, donc ReturnType<() => Tup<L,[F,...R]>> ne fera pas l'affaire, mais ReturnType<ConditionalType> fera l'affaire


0 commentaires

1
votes

TypeScript 4.1 a introduit les types conditionnels récursifs.

Ils permettent d'implémenter une fonction d'inversion de tuple comme ceci:

type Reverse<Tuple> = Tuple extends [infer Head, ...infer Rest]
       ? [...Reverse<Rest>, Head] : [];

const test: Reverse<[1,2,3,4]> = [4,3,2,1];


0 commentaires