Машинопись, универсальные средства и перегрузка

#javascript #typescript #generics #functional-programming #overloading

Вопрос:

Я работаю над реализацией некоторых функций в Typescript, которые я хотел бы перегрузить и которые также используют универсальные средства. Я совершенно сбит с толку этим результатом:

*Обратите внимание, что я удалил код, который не вызывает проблемы, поэтому, пожалуйста, не обращайте внимания на бесполезность фактических функций.

Это работает:

 export function persistContactData<T>(
  contactData: T,
  callback?: () => void
): void;
export function persistContactData<T>(
  { contactData }: { contactData: T },
  callback?: () => void
): void;
export function persistContactData<T>(
  { contactData }: { contactData: T },
  callback?: () => void
) {
  // implementation
}
 

Это не так (только в первом есть ошибка):

 
// *** Compile error: "This overload signature is not compatible with its implementation"
//
export function getPersistedContactData<T>(
  contactId: string,
  callback: (result?: T) => void
): void;

// No more errors, and if I remove the above signature everything is fine.
export function getPersistedContactData<T>(
  { contactId }: { contactId: string },
  callback: (result?: T) => void
): void;
export function getPersistedContactData<T>(
  { contactId }: { contactId: string },
  callback: (result?: T) => void
) {
  // implementation
}
 

Я озадачен тем, в чем здесь проблема, но я предполагаю, что что-то связано с тем, как используется общий параметр? Но, похоже, это не должно иметь значения.

(Я использую машинописный текст 3.9.3)

Изменить: Я обновил без каких-либо неизвестных типов

Комментарии:

1. Что такое PersistContactData ? Если это важно, не могли бы вы дать его определение? Если это не важно, не могли бы вы удалить его? В идеале, когда ваш пример кода помещается в автономную среду разработки, такую как игровая площадка TypeScript (ссылка) , единственными проблемами, которые могут возникнуть, должны быть те, о которых вы спрашиваете.

2. Если я позвоню getPersistedContactData("foo", x => x); , какой, по-вашему, должна contactId быть переменная внутри реализации getPersistedContactData() ? Это не будет string «а». Значение "foo" не имеет contactId свойства, поэтому вы делаете что-то странное. Не уверен, в чем смысл этого, но, возможно, вам следует исправить это вот так … и если это не поможет, вы, возможно, захотите подробнее остановиться в вопросе о том, что вы пытаетесь сделать. Удачи!

3. Хороший момент, я удалил все ненужные и неопределенные типы, так что теперь проблему будет легче увидеть.

Ответ №1:

Проблема в том, что универсальный параметр позволяет компилятору предположить, что форма может определять ожидаемый тип, поскольку фактическая реализация будет определять фактические формы параметров.

Это можно увидеть, если удалить все универсальные типы и вместо них использовать фактические типы.

Это сработает (но, вероятно, на самом деле это не то, что задумано):

 export function persistContactData<T>(
  contactData: T,  // <---- What is T?  ┐( ̄~ ̄)┌  Could be the right shape?
  callback?: () => void
): void;
export function persistContactData<T>(
  { contactData }: { contactData: T },
  callback?: () => void
): void;
export function persistContactData<T>(
  { contactData }: { contactData: T },
  callback?: () => void
) {
  // implementation
}
 

Этого не будет:

 // Error
export function persistContactData(
  contactData: string,  // <---- string is not compatible with the implementation
  callback?: () => void
): void;
export function persistContactData(
  { contactData }: { contactData: string },
  callback?: () => void
): void;
export function persistContactData(
  { contactData }: { contactData: string },
  callback?: () => void
) {
  // implementation
}