Почему оператор && выдает тип второго операнда

StackOverflow https://stackoverflow.com//questions/12693787

  •  12-12-2019
  •  | 
  •  

Вопрос

Спецификация TypeScript гласит в §4.15.6 о && оператор:

Оператор && допускает, чтобы операнды были любого типа, и выдает результат того же типа, что и второй операнд.

В Javascript && operator возвращает первый операнд, если он ложный, в противном случае он возвращает второй операнд (см. ECMA-262, §11.11).

Это означает, что если левый операнд является ложным, && вернет значение, соответствующее типу левого операнда.Например,

typeof ( false && {}      ) === "boolean" // true
typeof ( ''    && 1       ) === "string"  // true
typeof ( null  && "hello" ) === "object"  // true
typeof ( NaN   && true    ) === "number"  // true

Машинописный текст, согласно приведенному выше правилу, будет неправильно предсказать, какие типы приведенных выше выражений будут Object, Number, String и Boolean, соответственно.

Я что-то упускаю?Есть ли веская причина для создания типа && выражение соответствует типу второго операнда?Разве тип результата не должен вести себя как || operator, и возвращает наилучший общий тип из двух операндов, и Any если нет наилучшего общего типа?

Это было полезно?

Решение

Короче говоря, здесь нет решения, которое устраивало бы всех.

Рассмотрим эту распространенную идиому:

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.Правила для этих типов следующие:

  1. Truthy<T> ведет себя точно так же, как T
  2. Вы не можете получить доступ ни к каким свойствам Falsy<T>
  3. Выражение типа 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 введите, потому что тип, соответствующий всем необходимым вам спецификациям, уже существует.

Это немного похоже на то, как если бы вы дали кому-то коробку и сказали: "Это либо пустая коробка для мусора, либо полная коробка вторсырья".Вы можете смело выбрасывать содержимое коробки в мусорное ведро.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top