Учитывая значение типа T extends infer R ? R : never
, компилятор почти наверняка не сможет вывести что-либо полезное для T
(поскольку он будет склонен откладывать оценку такого условного типа до тех пор, пока не станет слишком поздно для T
быть Прогнозные). Поскольку этот тип по существу эквивалентен T
, мы просто будем использовать T
в дальнейшем.
Я думаю, что подпись и реализация wrap()
должны выглядеть следующим образом:
function wrap<T extends ((...args: any[]) => any)>(
wrapped: T & { flag?: string }): T & { flag?: string } {
let wrapper = function () {
// ...
return wrapped(...arguments);
} as T & { flag?: string };
wrapper.flag = wrapped.flag;
return wrapper;
}
То есть мы просто будем использовать параметр c generi T
для представления типа функции и оставим {flag?: string}
в качестве отдельного не универсального c типа объекта, с которым T
будет быть пересеченным. Причина, по которой вам нужно сделать что-то подобное, связана с правилами присваивания дополнительных свойств:
В TypeScript тип объекта отсутствует свойство считается назначаемым для объекта с необязательно свойство любого типа. Например, тип {foo: string}
присваивается типу {foo: string, bar?: number}
. Если у вас есть тип c типа T extends {foo: string, bar?: number}
, возможно, что T
будет {foo: string}
, при этом полностью отсутствует свойство bar
.
В вашем случае, если у вас есть универсальный c тип T extends ((...args: any[])=>any) & {flag?: string}
и вы передаете функцию без известного свойства flag
в качестве сайта вывода для T
, компилятор выведет T
как тип функции без свойства flag
. И тогда выход функции также не имеет свойства flag
, и вам грустно.
Чтобы гарантировать, что компилятор интерпретирует как входные, так и выходные данные функции как имеющие необязательное свойство flag
нам нужно явно включить его как во входные, так и в выходные данные и не дать компилятору шансов потерять его.
Okay; надеюсь, это поможет; удачи!
Детская площадка ссылка на код