Как удалить ключ / свойство из типа функции

Как удалить name из функции следующего типа:

type Func = {
  (): number
  name: string
}

Omit<Func, 'name'> приведет к never.

Playground ссылка


person Jacob    schedule 21.09.2020    source источник
comment
Вот что интересно, он теряет подпись вызова. Он сохраняет другие свойства (если они есть), но теряет сигнатуру вызова. (FWIW, я не думаю, что это вопрос условных типов, но я не уверен, что убрать тег. :-))   -  person T.J. Crowder    schedule 21.09.2020
comment
(Примечание: функции JavaScript всегда имеют свойство name (независимо от того, сообщаете ли вы об этом TypeScript), если только вы не играете в игры, чтобы избавиться от него, но проблема не в этом.)   -  person T.J. Crowder    schedule 21.09.2020
comment
keyof в Omit не поймает подпись вызова. Самым простым решением, вероятно, является создание двух различных типов - одного для функции и одного для объекта, которые затем пересекаются. Или вы извлекаете подпись - посмотрите:   -  person ford04    schedule 21.09.2020
comment
Извлечь сигнатуру вызова из типа или этого one.   -  person ford04    schedule 21.09.2020


Ответы (1)


Вы не можете этого сделать, потому что name является частью специального встроенного Function интерфейса, от которого наследуются все вызываемые объекты в TypeScript. Как только компилятор видит, что тип вызывается, он будет иметь namebind, и call, и apply, и т. Д.). Вы не сможете расширить тип, чтобы удалить эти ключи.

См. microsoft / TypeScript # 27575 для канонической проблемы по этому поводу. Я не знаю, что там что-то случится, но вы должны пойти туда, чтобы описать свой вариант использования и поставить отметку, если вы хотите повысить вероятность того, что проблема будет решена.

В любом случае, самое близкое, что вы сможете здесь получить, - это иметь name типа never, что является сужением, а не расширением:

type MyFunc = {
  (): number;
  readonly name: never;
};

Вы все еще можете назвать это:

declare const f: MyFunc;
const num = f(); // okay

И хотя он имеет name:

f.name; // no error here, but

Этот name больше не рассматривается как пригодный для использования string тип:

f.name.toUpperCase(); // error
// Property 'toUpperCase' does not exist on type 'never'.

Если вы говорили о другом свойстве, которое не встроено в Function, например

type MyFuncTwo = {
  (): number;
  title: string;
  age: number;
}

тогда вы можете удалить их, но не с помощью Omit<>, который является отображаемым типом. Сопоставленные типы пропускают сигнатуры вызова / построения. Для этого тоже есть открытая проблема: microsoft / TypeScript # 29261. Чтобы обойти это, вам нужно будет создать свой собственный сопоставитель типов, который повторно добавляет сигнатуру вызова:

type MyOmit<T, K extends PropertyKey> =
  (T extends (...args: infer A) => infer R ? (...args: A) => R : unknown) & Omit<T, K>;

Это работает для приведенного выше примера:

type MyFuncThree = MyOmit<MyFuncTwo, "title">;
// type MyFuncThree = (() => number) & Pick<MyFuncTwo, "age">

но есть всевозможные крайние случаи, связанные с перегрузками и, возможно, дженериками. Если вы действительно хотите увидеть обходной путь, вы можете перейти на # 29261, поставить ему ???? и описать свой вариант использования.


площадка ссылка на код

person jcalz    schedule 21.09.2020