Сохранение типов массива массивов в TypeScript

У меня есть функция, которая сортирует N массивов на основе первого:

export function sortArraysTogether<T>(
  arrays: T[][],
  comparator = (a, b) => (a < b ? -1 : a > b ? 1 : 0)
): T[][] {

Итак ([[20, 10, 30], ['bob', 'alice', 'charlie']])[[10, 20, 30], ['alice', 'bob', 'charlie']]

Проблема в том, что массивы, которые я передаю, относятся к разным типам, поэтому TS в данном случае жалуется, что Number[] is not assignable to string[]

Как исправить T или, скорее, сопоставить тип возвращаемого значения?

Ищете порядок, который нужно сохранить, поэтому приведенное выше должно возвращать эквивалент [number[], string[]]

TypeScript не очень любит синтезировать объединения. Вы можете создать T тип элемента arrays (вместо объединения типов элементов), как показано в этой ссылке на игровую площадку . Соответствует ли это вашим потребностям? Если да, то напишу ответ или найду подходящий источник дублирования. Если нет, пожалуйста, отредактируйте, чтобы уточнить, чего не хватает.

jcalz 21.07.2024 16:49

(см. предыдущий комментарий). Кроме того, из этого примера неясно, беспокоят ли вас ошибки в sortArr([]) (нет первого массива) или в sortArr([[2, 1], []]) (массивы имеют несовпадающую длину), или вам нужен возвращаемый тип для отслеживания порядка, поэтому sortArr([[2,1],["a","b"],[true, false]]) возвращается (number | string | boolean)[][] или если вернется [number[], string[], boolean[]]. Это имеет значение?

jcalz 21.07.2024 16:58
T extends any[] кажется именно тем, что мне нужно (думаю; я сейчас разговариваю по телефону, но мне бы хотелось, чтобы порядок сохранялся, а не возвращался тип объединения), спасибо :) Несовпадения длин на самом деле не применяются в TS, поэтому я в таком случае я бросаю. По сути, я просто хочу, чтобы тип «прошел», без изменений.
user26359422 21.07.2024 17:15

«Несоответствия длины на самом деле не подлежат принудительному исполнению» Кортежи существуют в TS, поэтому несоответствия длины подлежат принудительному исполнению, см. эту ссылку, когда эта информация сохранена. Что нам здесь делать? Кажется, что вы в основном ищете только T extends any[], но вы также говорите, что порядок должен быть сохранен, а для этого требуются сопоставленные типы. Есть разные способы сделать это в зависимости от ваших потребностей. Пожалуйста, просмотрите различные ссылки на игровые площадки, когда доберетесь до компьютера, и дайте мне знать, как вы хотите действовать.

jcalz 21.07.2024 17:29

На самом деле, глядя на .dts, а это единственное, что я могу делать на своем телефоне, кажется, что конкретные типы теряются. Есть ли способ сохранить порядок? Надеюсь, не перегружая подпись массивами 1..10.

user26359422 21.07.2024 17:30

Соответствие длин массивов не является обязательным, например. если бы я получил массивы из вызова API неизвестной длины. Кортежи — это подмножество массивов;)

user26359422 21.07.2024 17:31

Возможно, когда вы доберетесь до настоящего компьютера, вы сможете просмотреть мои ссылки на игровую площадку (например, вот эта , которая не заботится о несоответствии длины каждого элемента входного аргумента, но сохраняет другие данные), поиграть с ними с помощью различных варианты использования, дайте мне знать, если какой-либо из них соответствует вашим потребностям, а затем отредактируйте вопрос, чтобы убедиться, что вы указываете там свои требования (какие порядки массивов вас интересуют и т. д.).

jcalz 21.07.2024 18:01

Нет, просмотреть его на телефоне было нормально, мне просто нужно было посмотреть на .d.ts, так как на типы нельзя наводить курсор. Я просто не думал о порядке, когда изначально задавал вопрос. Спасибо, что заметили :) Какова цель extends [any, ...any[]]? Разве это не излишне? И после того, как с ним поигрались, отображение выглядит так, как будто оно работает отлично. Я понятия не имел, как это написать в ТС, лол.

user26359422 21.07.2024 18:31
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
8
92
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В дальнейшем я буду полностью игнорировать comparator. Я также предполагаю, что вы не хотите обращать внимание на длину каждого элемента массива (поэтому sortArraysTogether([["a","b"], [1,2,3]]) не будет ошибкой, даже если во втором элементе слишком много записей).

Я предполагаю, что вас волнует порядок элементов arrays и тип возвращаемого значения, поэтому sortArraysTogether([["a"],[1],[true]]) должно быть [string[], number[], boolean[]], а не (string | number | boolean)[][]. Это означает, что вы действительно не хотите T[][], даже если бы могли T работать. Действительно, вы не хотите, чтобы тип вывода был простым массивом формы ⋯[], потому что он неупорядочен. Тип вывода должен быть универсальным , то есть это может быть кортеж, который меняется в зависимости от типа ввода.

Наконец, поскольку вас заботит порядок ввода, вы также можете потребовать, чтобы был хотя бы один элемент, поэтому sortArraysTogether([]) должно быть ошибкой.


Учитывая эти требования, sortArraysTogether() должен выглядеть так:

declare function sortArraysTogether<T extends [any, ...any[]]>(
    arrays: { [I in keyof T]: T[I][] },    
): { [I in keyof T]: T[I][] };

Здесь функция является общей для T, типа каждого элемента arrays. Итак, если вы позвоните sortArraysTogether([[0],["a"],[true]]), то T будет [number, string, boolean]. Я включил T в открытый кортеж [any, ...any[]]. Это дает TypeScript намек на то, что вам важен порядок, и требует, чтобы входные данные содержали хотя бы один элемент.

Типом arrays и типом вывода являются {[I in keyof T]: T[I][]}, тип отображаемого кортежа , который выражает тот факт, что каждый элемент ввода arrays и вывода сам по себе является массивом соответствующего элемента T. Итак, если T равно [A, B, C, D], то тип arrays и возвращаемый тип — [A[], B[], C[], D[]].

Давайте проверим это:

const z = sortArraysTogether([[20, 10, 30], ['bob', 'alice', 'charlie'], [1, 3, 10]]);
//    ^ const z: [number[], string[], number[]]

sortArraysTogether([]); // error!
//                 ~~
// Argument of type '[]' is not assignable to parameter of type '[any[], ...any[][]]'.

Выглядит неплохо.

Детская площадка, ссылка на код

Другие вопросы по теме