spooky_2020
@spooky_2020
А меня Сережа зовут.

Что не так с сигнатурой перегрузки функции?

Линтер недоволен и выдает вот такое:
This overload signature is not compatible with its implementation signature .ts(2394)
The implementation signature is declared here.

TypeScript версии 4.4.3

Сама реализация:
function getProductCollection(func: (error: Error,        data: null,                  info: string) => any): void;
function getProductCollection(func: (error: null,         data: ProductUnit[],         info: string) => any): void;
function getProductCollection(func: (error: null | Error, data: ProductUnit[] | null,  info: string) => any): void { }

В чем проблема? Что я упустил?
Или в этой ситуации, эти два варианта колбэка считаются одним и тем же параметром, несмотря на то что его собственные аргументы разные?
  • Вопрос задан
  • 1133 просмотра
Решения вопроса 1
bingo347
@bingo347 Куратор тега TypeScript
Crazy on performance...
Реализация перегрузки должна содержать в каждом аргументе юнион из всех возможных комбинаций, то есть в Вашем случае так:
function getProductCollection(func:
    | ((error: Error, data: null, info: string) => any)
    | ((error: null, data: ProductUnit[], info: string) => any)
): void {}

Дело в том что тип
((error: Error, data: null, info: string) => any) | ((error: null, data: ProductUnit[], info: string) => any)
Это совершенно не тоже самое, что
(error: null | Error, data: ProductUnit[] | null,  info: string) => any
Ну и кстати, перегрузка в таком случае не особо нужна, и даже вредна.

Так же у такого типа есть 2 проблемы:
1. Колбэк func не вызвать нормально, так как без каста все аргументы обобщаться до типа never
2. Код вызывающий getProductCollection не сможет получить нормальные типы для колбэка, ему нужно будет явно указать типы 1 из вариантов, что опять же делает такой тип крайне бесполезным.

Можно сделать перегрузку самого колбэка:
function getProductCollection(func: {
    (error: Error, data: null, info: string): any;
    (error: null, data: ProductUnit[], info: string): any;
}): void {}
Это защитит внутренности getProductCollection от его неправильного вызова, но снаружи, Вы получите в колбэк обобщенный тип:
(error: null | Error, data: ProductUnit[] | null,  info: string) => any
Это заставит вызывающий код делать или лишние проверки, или кастовать типы, так что если не нужны сильные гарантии в пределах одной функции, то можно обойтись простым вариантом:
function getProductCollection(func: (error: null | Error, data: ProductUnit[] | null,  info: string) => any): void { }


Можно конечно заморочиться

Но работать это будет весьма ограничено:
https://www.typescriptlang.org/play?#code/C4TwDgpg...


P.S. не используйте тип any никогда, в Вашем случае лучше использовать тип void в качестве возвращаемого типа для колбэка, если Вы его никак не используете.

Ну и еще, взгляните на типизацию ноды:
https://github.com/DefinitelyTyped/DefinitelyTyped...
https://github.com/DefinitelyTyped/DefinitelyTyped...
Может не стоит усложнять использование Вашей функции вариативностью типов для data?
И почему бы вообще не использовать промисы вместо колбэков?
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
WblCHA
@WblCHA
Что я упустил?

Ты упустил то, что у тебя в оверлоаде частный случай функции из имплементации, а должно быть наоборот.
Сейчас если передать этот калбек, к примеру:
(error: Error,        data: null,                  info: string) => any

То в самой функции нам ничего не мешает вызвать кб с null вместо Error.
Вот так будет работать:
function getProductCollection(func: (error: null | Error, data: ProductUnit[] | null, info: string) => any): void;
function getProductCollection(func: (error: Error, data: null, info: string) => any): void { }

Но это не то.

В любом случае, самый главный вопрос, который я задал в коментах, для чего тут вообще перегрузка? Тут тебе юнион нужен. И то вопрос насколько он действительно нужен.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы