Выведите тип обертки из упакованной функции - PullRequest
0 голосов
/ 08 апреля 2020

Цель состоит в том, чтобы вывести тип оболочки из функции-обертки, то есть тип возврата из типа параметра.

Я не смог добиться этого с помощью infer:

function wrap<T extends ((...args: any[]) => any) & { flag?: string }>(wrapped: T extends infer R ? R : never): T {
        let wrapper = function () {
            // ...
            return wrapped(...arguments);
        } as T;

        wrapper.flag = wrapped.flag;

        return wrapper;
}

let wrapped = (a: number, b: number) => `${a}{b}`;

// wrapper is ((...args: any[]) => any) & { flag?: string }
// should be ((a: number, b: number) => string & { flag?: string }
let wrapper = wrap(wrapped);

// foo is any
// should be string
let foo = wrapper('invalid');

Как это можно сделать в этом случае без явного указания типа оболочки?

1 Ответ

1 голос
/ 09 апреля 2020

Учитывая значение типа 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; надеюсь, это поможет; удачи!

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

...