Вы на самом деле не перегружаете функцию так, как вы думаете.Перегруженная функция имеет упорядоченный список сигнатур вызовов , которые видимы для вызывающих функций и не имеют реализации (они заканчиваются на ;
, а не {...}
), и один сигнатура реализации , которая видна для реализации функции.Якобы вы хотите, чтобы звонящие, а не просто реализация, видели подпись publish<T>(message: Message<T>, payload: T): void
.Если это так, вам нужно сделать что-то вроде этого:
// call signatures
function publish(message: Message<never>, payload?: never): void;
function publish<T>(message: Message<T>, payload: T): void;
// implementation signature
function publish<T>(message: Message<T>, payload: T): void {
// ...
}
Это должно исправить вашу проблему, как указано.
Кроме того, обратите внимание, что это не рекомендуется иметь общий тип, например
type Message<T> = { id: string };
, где параметр типа не используется.Система типов TypeScript в основном структурная , а не номинальная, что означает, что если два типа имеют одинаковую структуру , то они имеют одинаковый тип, даже если вы используете разные имена для ссылки на них.В этом случае Message<never>
и Message<number>
оба { id: string }
, и, следовательно, они одного типа.
Возможно, что компилятор будет обрабатывать выражение, явно напечатанное как Message<never>
, в отличие от выражения, явно напечатанного как Message<number>
, и что ваши перегрузки будут вести себя так, как вы хотите.Но нет никакой гарантии, что это всегда будет работать, и странные вещи могут случиться, когда этого не произойдет.
Обычная мудрость здесь - использовать параметр типа где-то в структуре вашеготип.Даже что-то вроде
type Message<T> = { id: string; __messageType?: T };
иногда достаточно, чтобы все заработало, хотя во время выполнения не должно быть никакого свойства __messagetype
.
И вам также может понадобиться быть осторожным с подтипами и супертипами, так как даже в приведенном выше определении Message<T>
есть Message<never>
, являющийся подтипом любого Message<T>
, то есть вы можете вызвать publish(NeverMessage, "hello there");
без ошибок,Значение NeverMessage
будет восприниматься как действительное Message<"hello there">
.Чтобы предотвратить , что , вам нужно сделать Message<T>
инвариантом в T
, что может быть достигнуто, если вы включили --strictFunctionTypes
с помощьюсвойство функции, подобное этому:
type Message<T> = { id: string; __messageType?: (x: T) => T };
И вам также нужно расширить сигнатуру реализации:
function publish(message: Message<never>, payload?: never): void;
function publish<T>(message: Message<T>, payload: T): void;
function publish<T>(message: Message<T> | Message<never>, payload?: T): void {
// ...
}
Это приведет к
publish(NeverMessage); // okay
publish(NumberMessage, 10); // okay
publish(NeverMessage, "hello there"); // error!
.... но я отвлекся, потому что ты не спрашивал об этом.10
Ответ на ваш главный вопрос: не забудьте добавить отдельную сигнатуру реализации.
Хорошо, надеюсь, это поможет;удачи!
Ссылка на код