Я потратил много времени, пытаясь написать механическое объяснение того, почему определенные выражения, такие как expr1 || expr2 && expr3
, действуют в качестве защитников типов в определенных ситуациях, а не в других. Это закончилось тем, что стало несколькими страницами и все еще не учитывало все случаи в ваших примерах. Если вам интересно, вы можете посмотреть код, реализованный для операторов выражений в microsoft / TypeScript # 7140 .
Более высокоуровневое объяснение того, почему существует это ограничение и подобные ему: когда вы, человек, видите ценность типа союза, вы можете решить проанализировать ее, представив, что будет произойдет, если значение будет сужено для каждого члена этого типа, для всей области, где это значение существует. Если ваш код ведет себя хорошо для каждого такого случая анализа, то он ведет себя хорошо для полного объединения. Это решение, по-видимому, принимается исходя из того, насколько вы заботитесь о поведении рассматриваемого кода или о каком-либо другом когнитивном процессе, который мы не можем надеяться воспроизвести с помощью компилятора.
Компилятор может выполнить этот анализ все время , для каждого возможного выражения с типом union, с которым оно сталкивалось. Мы могли бы назвать это «автоматизированным c анализом потока распределенного управления», и было бы полезно почти всегда создавать желаемое поведение защиты типа. Недостатком является то, что компилятору потребуется больше памяти и времени, чем вы готовы потратить, и, возможно, больше, чем человечество может потратить из-за комбинаторного взрыва, который происходит, поскольку каждое дополнительное выражение типа объединения оказывает мультипликативный эффект на требуемые Ресурсы. Алгоритмы экспоненциального времени не годятся для хороших компиляторов.
Иногда я хотел иметь возможность намек на то, что конкретное значение типа объединения в определенной области видимости должно проанализировать таким образом, и я даже подал запрос на такой «анализ потока распределенного управления opt-in» (см. microsoft / TypeScript # 25051 ), но даже это потребовало бы больших усилий по разработке для реализации и будет отклоняться от целей проектирования TS по включению JS шаблонов проектирования, не требуя от разработчика слишком тщательного анализа потока управления.
Итак, в итоге разработчики языка TypeScript реализуют эвристику, которая выполняет такой анализ в ограниченных областях, которые позволяют обычные и идиоматические c JavaScript шаблоны кодирования. Если код, подобный (a ?? null) && fs(a)
, не считается идиоматическим c и достаточно традиционным для разработчиков языков (это частично субъективно и частично зависит от изучения корпуса реального кода), и если его реализация приведет к большой производительности компилятора штраф, тогда я не ожидал бы, что язык его поддержит.
Некоторые примеры:
microsoft / TypeScript # 12184 : поддержка «сохранения» msgstr "результат защиты типа в константу (как ваш пример something
) для дальнейшего использования. Это открытое предложение, помеченное как «пересмотр» со зловещим провозглашением языковым архитектором, что было бы трудно сделать это в качественной форме. Это может быть идиоматизм c, но это может быть сложно реализовать эффективно.
microsoft / TypeScript # 37258 : поддержка последовательных защит типа, в которых выполняются сужения несколько коррелированных переменных одновременно. Он закрыт как слишком сложный, потому что, чтобы избежать алгоритма экспоненциального времени, вам нужно жестко закодировать его с небольшим количеством проверок, что в целом не очень полезно. Предложение от сопровождающих языка: используйте больше идиоматических c проверок.
Так что это самый близкий к этому официальный или официальный ответ. Надеюсь, поможет; удачи!