#typescript #types
#typescript #типы
Вопрос:
type ResolverFn = () => any;
// type Notifications = () => any | number; // works as expected
type Notifications = ResolverFn | number;
// when using the named function, ResolverFn, it fails with error:
// "Cannot invoke an expression whose type lacks a call signature. Type 'Notifications' has no compatible call signatures."
// but it works with the unnamed () => any
type Query = {
notifications: Notifications;
};
const Query: Query = {
notifications() {}
};
const notifications: Notifications = () => {};
notifications();
Query.notifications();
Приведенный выше пример очень прост, и он вычитается из более сложного. На самом деле не существует типа, сигнатура которого является либо функцией, либо числом. Здесь это просто используется для демонстрации разницы в поведении.
Есть другие вопросы, связанные с этой ошибкой, но я не смог найти ответ на мой конкретный вопрос, который:
Почему существует различное поведение с именованной и неназванной функциями? Это ожидаемое поведение? Почему? Есть ли обходной путь? Предположим, что проблема исходит из внешнего пакета, который мы не можем изменить, даже если он может быть неправильным.
// type Notifications = () => any | number; // works as expected
type Notifications = ResolverFn | number;
// when using the named function, ResolverFn, it fails with error:
// «Cannot invoke an expression whose type lacks a call signature. Type ‘Notifications’ has no compatible call signatures.»
// but it works with the unnamed () => any
type Query = {
notifications: Notifications;
};
const Query: Query = {
notifications() {}
};
const notifications: Notifications = () => {};
notifications();
Query.notifications();» rel=»nofollow noreferrer»>Typescript repl
Ответ №1:
Причина, по которой встроенный тип функции «работает», заключается в том, что он не выполняет то, что вы думаете: он описывает функцию, возвращающую any | number
из-за правил приоритета. Обратите внимание на разницу:
// A function returning either any or number
type A = () => any | number;
// Either a function returning any — or a number
type B = (() => any) | number;
И причина, по которой в противном случае это не работает, заключается в том, что неясно, что notifications
относится к типу функции, это также может быть число, а числа не вызываются.
Как указано в ответе @Przemyslaw Pietrzak, используйте защиту типа, чтобы сузить тип:
if (typeof notifications === "function") {
notifications();
}
Комментарии:
1. О, facepalm был сложным. Не могли бы вы просто добавить решение ` if (typeof query.notifications === ‘function’) ` для полноты картины?
2. Готово! Я также ссылался на ответ Пшемыслава Пьетржака, поскольку он указал на это первым.
Ответ №2:
Тип уведомления о просмотре может быть либо числом, либо функцией. Итак, в последней строке TS не уверен, что Query.notifications
может быть вызван safety, потому что это может быть также number, и в этом случае код выдаст ошибку во время выполнения.
Чтобы предотвратить эту ошибку, добавьте оператор if:
if (typeof query.notifications === 'function') {
query.notifications();
}
внутри if TS знает, что query.notifications
это не число, поэтому его можно безопасно вызвать.