Ответ 1
Короче говоря, здесь нет решения, которое понравится всем.
Рассмотрим эту общую идиому:
var customer = GetCustomer(...); // of type 'Customer'
var address = customer && customer.address;
if(address) {
printAddressLabel(address); // Signature: (Address) => void
} else {
// Couldn't find the customer or the customer has no address on file
}
Было бы очень сложно отказаться и решить, что "адрес" - "любой", потому что между клиентом и адресом нет лучшего общего типа.
В большинстве случаев, когда && используется оператор, либо типы, уже совпадающие, либо && используется в способе объединения значений, как описано выше. В любом случае возврат типа правильного операнда дает пользователю ожидаемый тип.
В то время как безопасность типа технически ломается в данный момент, это не делает так, что может привести к ошибке. Либо вы собираетесь проверить результирующее значение правдивости (в этом случае тип более или менее неактуальен), либо вы собираетесь использовать презумптивный правый операнд для некоторой операции (пример выше делает оба).
Если мы посмотрим на приведенные вами примеры и притворимся, что левый операнд является неопределенно правдивым или фальшивым, а затем попытайтесь написать нормальный код, который будет работать с возвращаемым значением, он станет намного понятнее - вам просто нечего делать 'false && {} ', который уже не входит в "позицию" или "правность" аргумента.
Добавление
Поскольку некоторые люди не были убеждены выше, здесь другое объяснение.
Пусть на мгновение притворится, что система типа TypeScript добавила три новых типа: Truthy<T>
, Falsy<T>
и Maybe<T>
, представляющие возможные значения правды/фальши типа T
. Правила для этих типов следующие:
-
Truthy<T>
ведет себя точно так же, какT
- Вы не можете получить доступ к каким-либо свойствам
Falsy<T>
- Выражение типа
Maybe<T>
при использовании в качестве условия в блокеif
становитсяTruthy<T>
в теле того же блокаif
иFalsy<T>
в блокеelse
Это позволит вам делать такие вещи:
function fn(x: Maybe<Customer>) {
if(x) {
console.log(x.address); // OK
} else {
console.log(x.phone); // Error: x is definitely falsy
}
console.log(x.name); // Warning: x might be falsy!
}
Довольно хорошо. Теперь мы можем выяснить, что такое правила типа для && Оператор.
-
Truthy<T> && x
должна быть ошибка - если левая сторона известна как правдивая, вы должны просто написатьx
-
Falsy<T> && x
должна быть ошибка - если левая сторона, как известно, ложна,x
- недостижимый код -
Maybe<T> && x
должен производить... что?
Мы знаем, что результат Maybe<T> && x
будет либо ложным значением типа T
, либо x
. Он не может создать Truthy<T>
(если T
== тип x
, и в этом случае все это обсуждение является спорным). Позвольте называть этот новый тип Falsy<T> XOR Maybe<U>
.
Какими должны быть правила Falsy<T> XOR Maybe<U>
?
- Очевидно, вы не можете использовать для этого свойства
T
. Если значение имеет типT
, оно ложно и небезопасно для использования. - Вы должны использовать его как
Maybe<U>
, так какFalsy<T>
иFalsy<U>
имеют одинаковое поведение - Вы не должны использовать свойства
U
, потому что значение все равно может быть ложным. - Если вы используете его в тесте
if
, тогда он должен статьTruthy<U>
в блоке этого оператораif
Другими словами, Falsy<T> XOR Maybe<U>
Maybe<U>
. Он следует всем тем же правилам. Вам не нужно вообще усложнять систему типов, добавив этот странный тип XOR
, потому что тип, который соответствует всем требуемым спецификациям, уже существует.
Это немного похоже на то, чтобы дать кому-то коробку и сказать: "Это либо пустой ящик мусора, либо полный ящик вторсырья". Вы можете безопасно удалить содержимое коробки в мусорный ящик.