У меня есть функция, которая, учитывая другую функцию и список аргументов, вызывает эту функцию, предоставляет первый аргумент и пересылает список заданных аргументов, начиная со второго (в некоторой степени похож на bind). Затем возвращается результат данного аргумента.
Вызов
foo(anotherFunction, 1, '2');
вызовет anotherFunction
примерно так:
anotherFunction(someValue, 1, '2');
Проблема возникает с выводом типа, когда функция имеет параметр типа. Взгляните на этот код:
// First attempt to type foo
declare function foo1<A extends any[], R>(
fn: (arg1: any, ...args: A) => R,
...args: A
): R;
// Type of foo with the specific case the second parameter is a function
declare function foo2<A2 extends any[], R2, A extends any[], R>(
fn: (arg1: any, arg2: (...args: A2) => R2, ...args: A) => R,
arg2: (...args: A2) => R2,
...args: A
): R;
declare function bar<T>(a: number, fn: (a: number) => T): T;
// `result1: string`, OK
const result1 = bar(1, x => x.toString());
// ERROR: 'x' implicitly has an 'any' type
const result2 = foo1(bar, x => x.toString());
// No error and `result3: string`, OK but requires type annotation
const result3 = foo1(bar, (x: number) => x.toString());
// No errors but `result4: unknown`, not Ok (*)
const result4 = foo2(bar, x => x.toString());
// `result5: string`, OK but requires type annotation
const result5 = foo2(bar, (x: number) => x.toString());
Playground Link
Функция foo1
и foo2
- это два способа ввода функции foo
, и bar
- это функция, которая будет вызываться fooX
. В целом foo1
работает хорошо, но не делает хорошего вывода, если некоторые из приведенных аргументов являются функцией с параметрами типа. Функция foo2
учитывает конкретный случай c, что вторым аргументом является функция, которая работает немного лучше, но не совсем.
Вопрос1: Есть ли способ напишите такую функцию, учитывая, что любой аргумент может быть функцией? Случай, когда второй параметр является функцией, для меня гораздо более распространен, поэтому решение, учитывающее только это, все еще работает.
Идея состоит в том, что параметры функций, указанные в списке аргументов, будут выводиться без необходимости явной аннотации типа (или, по крайней мере, для первого аргумента, если это функция).
Вопрос2: Почему result4
выводится как unknown
, даже когда x
(параметр функции, строка, отмеченная (*)
) правильно выводится как number
?
РЕДАКТИРОВАНИЕ:
Я только что понял, что .bind()
также удаляет параметр типа:
declare function bar<T>(a: number, fn: (a: number) => T): T;
// boundBar: (fn: (a: number) => unknown) => unknown
const boundBar = bar.bind(undefined, 0);
// result1: unknown
const result1 = boundBar(x => x.toString());
Playground Link
Я думал, https://github.com/microsoft/TypeScript/pull/30215 здесь поможет, но, может быть, я был не прав.
Это ошибка или ограничение дизайна?