Можно ли распространить аргументы функции на массив универсальных типов?
Я пытаюсь добавить тип 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;
Это позволит потребителю передать функцию, которая принимает любое количество параметров и типов параметров, и возвращаемая функция будет правильно типизирована.
Ваше решение почти правильное, вам просто нужно сказать TS, что Args
ограничен массивом (в данном случае кортежем аргументов).
export type Foo<State> = <Args extends any[]>(
baz: (state: State, ...args: Args) => Partial<State>
) => (...args: Args) => any;
Разве
bar
иbaz
не должны также приниматьstate
? согласно вашим попыткам?