как написать тип Invert в машинописном тексте, чтобы инвертировать порядок кортежей

type a = [1,2,3]
type Invert<T extends any[] & {'0': any}> = ???
type b = Invert<a> // should yield [3,2,1]

Я застрял, чтобы выяснить определение типа Invert кортежа, а также типов Init и Last, хотя они могут быть построены друг из друга

что я пробовал:

  1. поместите тип в определение параметра функции и выведите часть Rest, этот подход получил только часть Tail с параметрами отдыха

person Minami    schedule 09.01.2020    source источник


Ответы (3)


Это работает, только если вы знаете длину массива:

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]

Обновлять

На самом деле существует решение (найдено здесь в проблеме машинописного текста проект):

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]

площадка Link

person iY1NQ    schedule 09.01.2020
comment
на самом деле, я хочу получить общую версию - person Minami; 09.01.2020
comment
Если вы имеете в виду определение типа, которое меняет местами любое количество записей массива, это невозможно. Как вы упомянули выше, для этого требуются операторы головы и хвоста, которые, в свою очередь, требуют оператора отдыха в сочетании с рекурсией для общих ограничений. Оба не существуют для дженериков. - person iY1NQ; 09.01.2020
comment
@Minami Мой последний комментарий не соответствует действительности, существует общая версия. Смотрите мой обновленный ответ. - person iY1NQ; 16.01.2020
comment
@ 1y1nq хорошее решение - person Minami; 17.01.2020

TypeScript 4.1 представил рекурсивные условные типы.

Они позволяют реализовать функцию обращения кортежа следующим образом:

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

const test: Reverse<[1,2,3,4]> = [4,3,2,1];
person rcode    schedule 24.11.2020

в коде машинописного текста 4.0 приблизиться к обратному типу намного проще, чем раньше, говоря

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

какое-то объяснение:

  1. тип прямой ссылки Reverse в typealias Reverse приведет к ошибке циклических ссылок.
  2. wrap Reverse type в типе функции (()=> Reverse) отключит ошибку циклических ссылок
  3. если выражение типа может разрешиться статически, компилятор попытается разрешить его, поэтому ReturnType<() => Tup<L,[F,...R]>> не поможет, но ReturnType<ConditionalType> сделает
person Minami    schedule 09.08.2020