TypeScript преобразовывает тип Tuple кортежа в Tuple (сглаживает Tuple)

у меня есть это

Type T = Params<[Tuple1, Tuple2]> // eg [[string], [number]]

Как из него сделать (сплющить)

Type Flatten<T> = Params<[string, number]> 

person luky    schedule 18.12.2019    source источник


Ответы (1)


Мы можем сделать это с помощью сопоставленных типов. Рассмотрим код:

type T = Params<[Tuple1, Tuple2]>

// utility type
type Flatten<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? T[K][0] : T[K]
}
type Result = Flatten<T>
// evaluates into [string, number]

const a: Result = ['a', 1] // correct value of the type

Обратите внимание, как работает Flatten:

  • [K in keyof T] - означает, что мы хотим иметь все ключи, поэтому в кортеже скажем, что элементы
  • T[K] extends any[] ? T[K][0] : T[K] - мы говорим, что если значение элемента в данном ключе является массивом, тогда дайте мне тип первого элемента этого массива (индекс 0), если не оставьте его как есть, так как нечего сглаживать

Если ваши кортежи учитывают более одного типа элемента, то приведенное выше решение будет принимать только первый. Таким образом, для кортежа [string, number] он создаст string. Если мы хотим собрать все возможные типы внутри кортежа, мы можем создать более сложный тип. Рассмотреть возможность:

type Flatten<T extends any[]> = {
  [K in keyof T]: T[K] extends any[] ? T[K][Exclude<keyof T[K], keyof any[]>] : T[K]
}
  • T[K] extends any[] ? T[K][Exclude<keyof T[K], keyof any[]>] : T[K] означает, что если наш элемент является массивом, я получаю типы всех элементов, но удаляю типы значений в прототипе массива.

В результате Flatten<Params<[string, number]>> выдаст [string | number]. Так что все зависит от вашей цели.


Последнее предложение: если вы не рассматриваете другие типы и только вложенные массивы / кортежи, мы можем избежать условных типов. Рассмотрим последнее решение:

type Flatten<T extends E[], E extends any[] = any[]> = {
  [K in keyof T]: T[K][Exclude<keyof T[K], keyof any[]>]
}

Вышеупомянутый тип более ограничен, поскольку работает только с [[]], но является более кратким и конкретным.

person Maciej Sikora    schedule 18.12.2019
comment
отлично работает, спасибо, только проблема, если это параметры функции, что она теряет имя параметра, например x: string, теперь оно становится param_0: string. лучше всего было бы что-то вроде [... TupleParams1, ... TupleParams2], но это не работает - person luky; 18.12.2019
comment
@luky, ты можешь быть яснее, слышишь, а не до конца понимаешь. Что нужно передать функции вне очереди? - person Maciej Sikora; 18.12.2019
comment
U может использовать тип результата, например - function f(...args: Flatten<T>) {} - person Maciej Sikora; 18.12.2019
comment
хм, на самом деле это два параметра двух функций, но я попробую еще раз, потому что вспомогательные параметры TS ‹› также фиксируют имена параметров, например x: string и т. д. - person luky; 18.12.2019
comment
Вы можете использовать его как два параметра, например function f(first: Flatten<T>[0], second: Flatten<T>[1]) {} - person Maciej Sikora; 18.12.2019
comment
проверить игровую площадку, место курсор над с (в) и г () в левом окне - person luky; 18.12.2019
comment
Да, видите, я имею в виду, что это по-другому показывает имя аргумента, я не уверен, что это можно исправить, извините. - person Maciej Sikora; 18.12.2019
comment
Еще одна проблема, тип Flatten отбрасывает частичные ключи, поэтому теперь требуются все. - person luky; 18.12.2019
comment
Решить не так-то просто. Я понимаю вас, но я думаю, что мы далеки от исходного вопроса. Я предлагаю создать еще один. Обратите внимание, что исходный вопрос вообще ничего не говорит об аргументах функции. - person Maciej Sikora; 18.12.2019