Это комбинация нескольких вещей, кусающих вас.
Основная проблема заключается в том, что компилятор не выполняет свой анализ потока управления , проходя по вызовам функций, находя реализацию этой функции и проверяя, находится ли состояние любых закрытых переменных изменилось. Это было бы «правильным» поведением, но компилятору было бы непозволительно дорого с точки зрения времени и памяти по существу моделировать работу каждой программы для отслеживания таких изменений состояния. Вопрос "когда вызывается функция, как должен компилятор предполагать ее побочные эффекты?" трудно ответить, и в GitHub есть обсуждение этого: microsoft / TypeScript # 9998 .
Текущий компилятор предполагает, что вызовы функций имеют никаких побочных эффектов. Таким образом, если a
сброшен до вызова wait()
, компилятор также будет считать его неустановленным. Это не так в вашем случае, но есть много, много случаев, когда это желаемое поведение. Это компромисс. Поэтому нам нужно найти обходной путь, при котором компилятор обрабатывает a
как «возможно установленный» после вызова wait()
, не полагаясь на то, что компилятор сделает это за нас.
Ваш второй подход, при котором вы инициализируете a
чем-то вроде null
или undefined
, является многообещающим, но, к сожалению, вы столкнулись с другой проблемой: если вы присваиваете значение переменной типа объединения, анализ потока управления сузит переменную тип. Таким образом, после let a: { bool: boolean } | null = null;
компилятор видит a
типа null
до тех пор, пока он не будет переназначен. См. micrsoft / TypeScript # 8513 для получения дополнительной информации. Опять же, это часто хорошо. В конце концов, если бы мы не пытались обойти другую проблему, вы бы хотели бы , чтобы компилятор думал, что a
- это null
там.
Обходной путь здесь (, косвенно упомянутый в вышеприведенной проблеме ), вероятно, использует утверждение типа , чтобы сказать компилятору трактовать null
не как тип null
, а как тип объединения { bool: boolean } | null
:
let a = null as { bool: boolean } | null;
Теперь вы можете позвонить wait()
, после чего предполагаемый тип a
не изменился (из-за # 9998) и остается объединением. Тогда другой код, показанный ниже, функционирует, как и ожидалось:
if (a === undefined || a === null) return;
alert(a.bool); // okay
Так что, да? Он не идеален ни в коем случае, но это лучшее из того, что я могу предложить, учитывая текущее воплощение TypeScript. Во всяком случае, надеюсь, что это помогает; удачи!
Детская площадка ссылка на код