@IvanIvanIvanIvanIvan

Что такое signature и implementation?

Я абсолютно новый человек в typescript. До этого писал только на js:
interface MyPosition {
    x: number | undefined,
    y: number | undefined,

}
interface MyPositionWithDefault extends MyPosition {
    default: string,
}
function position(): MyPosition
function position(a:number, b:number): MyPosition
function position(a:number): MyPositionWithDefault  //This overload signature is not compatible with its implementation signature.(2394)

function position(a?: number, b?:number) {
    if (!a && !b) {
        return {x: undefined, b: undefined}
    }
    if(a && !b) {
        return {x: a, b: undefined, default: a.toString()}
    }
    return {x: a, y: b}
}

TypeScript выдает ошибку This overload signature is not compatible with its implementation signature.(2394). Объясните пожалуйста что означает эта ошибка? И что такое вообще signature и implementation. И почему они не совместимы
  • Вопрос задан
  • 354 просмотра
Решения вопроса 1
bingo347
@bingo347 Куратор тега TypeScript
Crazy on performance...
Сигнатура функции - это по сути ее тип, который состоит из списка аргументов с типами и типа возвращаемого значения.
Имплементация функции - это функция с телом.
То есть следующие строки - это сигнатуры:
function position(): MyPosition
function position(a:number, b:number): MyPosition
function position(a:number): MyPositionWithDefault

Это тоже сигнатура: function position(a?: number, b?:number), но она так же является частью имплементации:
function position(a?: number, b?:number) {
    if (!a && !b) {
        return {x: undefined, b: undefined}
    }
    if(a && !b) {
        return {x: a, b: undefined, default: a.toString()}
    }
    return {x: a, y: b}
}


Перегрузки в TS работают по особенному, не так как в других языках. Все дело в том, что на выходе должен получится JS, в котором никаких перегрузок нет. Поэтому перегрузки работают только на уровне типов.
Поэтому Вы сначала перечисляете список сигнатур, которые станут типом функции для вызывающей стороны, а потом пишите имплементацию, у которой сигнатура должна быть обобщением всех перегрузок, так как именно она используется для проверки типов внутри функции.

Еще один важный момент для данного примера - это вывод типов. Если где-то тип не указать, то TS попробует его вывести, но делает он это весьма топорно - из первого значения которое будет присвоено переменной, ну и из первого return если речь идет о выводе возвращаемого значения функции.
В Вашем случае TS выведет возвращаемое значение имплементации из следующей строчки: return {x: undefined, b: undefined}
Тип такого значения будет:
interface ReturnTypeOfPosition {
  x: undefined
  b: undefined
}
Проблема тут в двух вещах, во-первых в поле b вместо поля y, во-вторых в отсутствии поля default.
Если исправить так:
function position(): MyPosition
function position(a: number, b: number): MyPosition
function position(a: number): MyPositionWithDefault
function position(a?: number, b?: number): MyPosition | MyPositionWithDefault {
    if (!a && !b) {
        return {x: undefined, y: undefined}
    }
    if(a && !b) {
        return {x: a, y: undefined, default: a.toString()}
    }
    return {x: a, y: b}
}
то все будет ок

Ну и еще важный момент про перегрузки, TS использует в месте вызова ту перегрузку, которая первой подошла по аргументам, пробуя их в том порядке, как они записаны у Вас в коде, сверху вниз. Соответственно остальные типы в месте вызова будут выводится из данного факта.

P.S. у меня в профиле есть ссылка на доклад по системе типов TS, про перегрузки там тоже есть. Система типов в TS полностью построена на математике множеств, если понять эту математику, то поймете и TS.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы