Почему использование оператора if-else приводит к ошибке компилятора TypeScript, если внешне идентичная конструкция тернарного оператора - нет?
Короткий ответ
TypeScript видит if-else
как оператор с несколькими выражениями, каждое из которых имеет независимые типы. TypeScript рассматривает тернар как выражение с типом объединения его истинной и ложной сторон. Иногда этот тип объединения становится достаточно широким, чтобы компилятор не жаловался.
Подробный ответ
Разве тернарный оператор и оператор if-else не эквивалентны?
Не совсем.
Разница проистекает из того, что тернарность является выражением . Здесь есть диалог , где Райан Кавано объясняет разницу между тернарным оператором и оператором if / else. Вывод состоит в том, что тип тернарного выражения представляет собой объединение его результатов true
и false
.
Для вашей конкретной ситуации тип тернарного выражения any
. Поэтому компилятор не жалуется. Ваш тернар представляет собой объединение типа input
и возвращаемого типа input.convert()
. Во время компиляции тип input
расширяет Container<any>
; поэтому тип возврата input.convert()
- any
. Так как объединение с any
равно any
, тип вашего троичного, ну, ну, any
.
Быстрое решение для вас - заменить any
на unknown
дюйм <TKey extends IDBValidKey | IDBValidKeyConvertible<any>
. Это приведет к тому, что как if-else, так и тройной вызовут ошибку компилятора.
Упрощенный пример
Вот ссылка на игровую площадку с упрощенным воспроизведением вашего вопроса. Попробуйте изменить any
на unknown
, чтобы посмотреть, как отреагирует компилятор.
interface Container<TValue> {
value: TValue;
}
declare function hasValue<TResult>(
object: unknown
): object is Container<TResult>;
// Change any to unknown.
const funcIfElse = <T extends Container<any>>(input: T): string => {
if (hasValue<string>(input)) {
return input.value;
}
return input;
};
// Change any to unknown.
const funcTernary = <T extends Container<any>>(input: T): string =>
hasValue<string>(input)
? input.value
: input;