Можно ли распространять уникальные общие типы в TypeScript?

Можно ли распространить аргументы функции на массив универсальных типов?

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

У меня есть базовое решение проблемы, но оно работает только с фиксированным числом параметров. Можно ли распространять общие параметры следующим образом?

Пример использования:

type Foo = // Generic solution here

const bar = foo((state, name: string, age: number));

bar('John', 22); // All good
bar('John', 'Doe'); // Type Error, 'Doe' is not a number

const baz = foo((state, firstName: string, lastName: string, age: number));

baz('John', 'Doe', 22)

Это для интеграции React Hook. Есть несколько действительно хороших примеров, когда провайдеры проделали большую работу, чтобы сделать безопасность типов TypeScript действительно простой для своих потребителей. Отличным примером является TypedUseSelectorHook из React Redux. https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-redux/index.d.ts#L556

Попытка 1 Решение с разбросом. Но, к сожалению, все типы являются объединением всех возможных типов.

export type foo<State> = <Args>(
    baz: (state: State, ...args: Args[]) => Partial<State>
) => (...args: Args[]) => any;

Попытка 2 Решение с «фиксированным» количеством параметров. Это работает, но автозаполнение показывает все параметры. И если потребитель попытается использовать большее количество типов, чем добавлено, TypeScript будет недоволен.

type foo<State> = <
    Arg0 = void,
    Arg1 = void,
    Arg2 = void,
    Arg3 = void,
    Arg4 = void,
    Arg5 = void
>(
    baz: (
        state: State,
        arg0: Arg0,
        arg1: Arg1,
        arg2: Arg2,
        arg3: Arg3,
        arg4: Arg4,
        arg5: Arg5
    ) => Partial<State>
) => (
    arg0: Arg0,
    arg1: Arg1,
    arg2: Arg2,
    arg3: Arg3,
    arg4: Arg4,
    arg5: Arg5
) => any;

То, что я хотел бы получить, это что-то вроде:

type Foo<State> = <PassedArgs>(
    baz: (
        state: State,
        ...args: PassedArgs // Error: A rest parameter must be of an array type.
    ) => Partial<State>
) => (args: PassedArgs) => any;

Это позволит потребителю передать функцию, которая принимает любое количество параметров и типов параметров, и возвращаемая функция будет правильно типизирована.

Разве bar и baz не должны также принимать state ? согласно вашим попыткам?

Titian Cernicova-Dragomir 21.06.2019 12:20
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой 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 для повышения производительности приложения путем загрузки модулей только тогда, когда они...
0
1
4 362
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Ваше решение почти правильное, вам просто нужно сказать TS, что Args ограничен массивом (в данном случае кортежем аргументов).

export type Foo<State> = <Args extends any[]>(
    baz: (state: State, ...args: Args) => Partial<State>
) => (...args: Args) => any;

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