Как я могу вывести типы аргументов нескольких функций в TypeScript

const foo = (a: string, b: string) => {
  console.info('foo', a, b);
};

const bar = (a: number, b: number) => {
  console.info('bar', a, b);
};

const factory =
  <M extends typeof foo | typeof bar>(method: M) =>
  (...args: Parameters<M>) => {
    method(...args);
  };

Я хочу создать фабрику нескольких функций (имеет разные аргументы)

Но TypeScript выдает ошибку ниже сообщения.

A spread argument must either have a tuple type or be passed to a rest parameter.

Возвращает ли Parameters кортеж типа утилиты?

Мне кажется, это ошибка TypeScript. Это работает, если вручную сделать функцию M extends (...args: Parameters<typeof foo | typeof bar>) => (ReturnType<typeof foo | typeof bar>).

Chayim Friedman 20.06.2024 17:39

Это ограничение конструкции, описанное в ms/TS#47615 . Рекомендуемый подход — сделать рефакторинг общим для списка параметров, а не для типа функции, как показано в этой ссылке на игровую площадку. Это полностью решает вопрос? Если да, то я напишу ответ с объяснением; если нет, то что мне не хватает?

jcalz 20.06.2024 17:46

@jcalz Это работает идеально! Спасибо :D

Hyesung Oh 21.06.2024 04:27
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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 для повышения производительности приложения путем загрузки модулей только тогда, когда они...
3
3
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

TypeScript не очень хорошо понимает общие условные типы ; в частности, он не всегда может просмотреть тип утилиты «Параметры<M>» для универсального типа функции M и понять, что выходные данные всегда можно расширять. Это считается ограничением дизайна TypeScript, как описано в microsoft/TypeScript#47615.

В соответствии с этой проблемой рекомендуемый подход — сделать функцию универсальной в списке аргументов A и возвращаемом типе R типа функции отдельно. Для вашего кода тип возвращаемого значения всегда void, поэтому мы можем сделать его просто универсальным в A:

const factory = <A extends Parameters<typeof foo | typeof bar>>(
    method: (...args: A) => void) => (...args: A) => {
        method(...args);
    };

Поскольку известно, что тип A из args является типом остальных параметров для method, вызов разрешен. И хотя для примера это не обязательно важно, A было ограничено до Parameters<typeof foo | typeof bar>, чтобы вы не могли передавать случайные функции в:

factory(foo)("a", "b"); // okay
factory(bar)(1, 2); // okay
factory((a: string, b: number) => { }) // error!

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

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

Похожие вопросы

Сопоставьте значения из NgForm с моделью машинописного текста, определенной в Angular
Могу ли я использовать файлы ts точно так же, как я использую файлы js?
Проблема вывода типа с массивом универсальных объектов конфигурации с разными внутренними типами, которые зависят от другого внутреннего свойства
Почему добавление круглых скобок удаляет «только для чтения [x: число]: число;» из этого типа?
Введите 'строка | логическое значение не может быть назначено для ввода «никогда» в машинописном тексте
Как добавить динамические метаданные на страницу [slug] в маршрутизаторе приложений next.js
Программно переключить свойство, нулевое или необязательное, на обязательное в Zod
Кортеж, который принимает только одно вхождение определенного типа
Как указать значение по умолчанию (но не ноль) в числовом типе в форме zod и response-hooks?
Тип «неизвестный» не может быть назначен типу «HttpEvent<any>». Попытка создать перехватчик HTTP в приложении Angular