Как использовать рекурсивный кортеж с переменным числом аргументов в качестве типа параметра функции

У меня есть надуманное рекурсивное определение кортежа:

type TupleRecursion<T> =
  T extends [infer HEAD, ...infer TAIL]
    ? [HEAD, ...TupleRecursion<TAIL>]
    : [];

а затем я пытаюсь ограничить параметры моей функции, используя этот тип. Я ожидаю, что такая функция разрешит любой кортеж:

function foo<T>(tuple: TupleRecursion<T>) {}

Однако когда я вызываю функцию с кортежем с двумя элементами:

test(["test", "hi"]);

Я получаю сообщение об ошибке «Источник имеет 2 элемента, но цель допускает только 0».

Почему это происходит? Как я могу заставить TS принимать кортеж любой длины и правильно определять его тип?

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

Это происходит потому, что TS пытается вывести T с помощью обратного сопоставления и неправильно определяет длину. Самый простой способ помешать этому — это обычно T & TupleRecursion<T>, а если вариант использования требует чего-то другого, вы можете попробовать T extends TupleRecursion<T> ? T : TupleRecursion<T>; оба показаны по ссылке на эту игровую площадку. Это полностью решает вопрос? Если да, то я напишу ответ; если нет, то что мне не хватает?

jcalz 17.06.2024 17:12
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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
1
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете изменить тип TupleRecursion для обработки базового случая, когда T — пустой кортеж. Вот обновленная версия типа TupleRecursion:

    type TupleRecursion<T> =
  T extends [infer HEAD, ...infer TAIL]
    ? [HEAD, ...TupleRecursion<TAIL>]
    : T extends []
      ? []
      : never;

Затем вы можете определить свою функцию foo следующим образом, используя обновленный тип TupleRecursion:

function foo<T extends any[]>(tuple: TupleRecursion<T>) {
  // Your function implementation here
}

Хм, я все еще не могу заставить его работать... я что-то упускаю? typescriptlang.org/play/?#code/…

wwohlers 17.06.2024 05:20
Ответ принят как подходящий
type ConvertRecursiveTuple<T> = T extends [infer One, ...infer Rest] 
 ? Rest extends []
   ? [One]
   : [One, ...ConvertRecursiveTuple<Rest>]
 : [];

function foo<T extends any[]>(tuple: T & ConvertRecursiveTuple<T>) {
  return tuple;
}
  
const a = foo(["hello", 123, false]);  

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

TS2344: тип, выведенный из свойства универсального аргумента, «не удовлетворяет ограничению», хотя тип работает нормально?
Общий тип TypeScript: рекурсивно делает все поля объекта необязательными, если только тип поля не является массивом
Машинописный текст, жалующийся на «T», может быть создан с другим подтипом ограничения «MyType»
Как сделать компонент Angular более универсальным, чтобы он мог принимать несколько типов данных в качестве @Input?
Универсальные типы с динамическим обязательным ключом определенного типа
Определение типа
Как создать универсальный компонент формы в Next.js 14 с помощью TypeScript и формы реагирования?
TypeScript: «Тип является универсальным и может индексироваться только для чтения. (2862)»
Создание общего контекста, который позволяет правильно выводить дочерние элементы внутри него
Машинописный текст не определяет тип значения ключа