querySelector может возвращать любой подтип Element. На веб-странице это почти наверняка будет либо HTMLElement, либо SVGElement. Они несовместимы, и все же TypeScript, кажется, рад, что я присвоил результат querySelector типу HTMLElement и получил доступ к свойствам, специфичным для HTMLElement. Почему не выдает ошибку?
Вот пример
// why no error on assuming it's going to be HTMLELement
// and not SVGELement or some other Element?
const foo: HTMLElement | null = document.querySelector("*");
if (foo !== null) {
console.info(foo.hidden);
}
Компилируется нормально, однако foo на самом деле может быть SVGElement.
Если я вручную задаю тип foo как SVGElement, то машинописный текст будет по праву жаловаться на доступ к свойству hidden.
Почему TypeScript не уловил ошибочное предположение, что возврат querySelector обязательно является HTMLElement?






Сигнатура метода
querySelector<E extends Element = Element>(selectors: string): E | null;
Определив возвращаемый тип как HTMLElement (см. Вывод типа), вы предоставили общий тип E. Ваш код эквивалентен
const foo = document.querySelector<HTMLElement>('*'); // HTMLElement | null
Единственное ограничение состоит в том, что E должно расширяться Element.
Это верно. Это один из тех случаев, когда вы, по сути, говорите компилятору, что вы знаете лучше всех. Однако это не предотвратит проблемы во время выполнения.
В машинописном тексте нет ничего плохого.
Из lib.dom.d.ts для определения querySelector (доступ, удерживая Ctrl + щелчок мышью по имени функции в хорошей IDE)
Мы будем найдены.
...
querySelector<E extends Element = Element>(selectors: string): E | null;
...
означает querySelector — это Общий, а по умолчанию — Element тип. Он вернется Element, если мы их не указали.
и мы могли бы явно указать аргументы generic.
const foo = document.querySelector<SVGElement>("*");//this will return SVGElement | null
if (foo) {
//use foo as SVGElement
}
или путем вывода аргумента универсального типа (не знаю, как вызвать машинописный текст, но в С++ есть аналогичный)
const foo:SVGElement | null = document.querySelector("*");//typescript will inference to document.querySelector<SVGElement>("*")
if (foo) {
//use foo as SVGElement
}
Итак, причина, по которой вы получаете HTMLElement, заключается в том, что Typescript выводит тип от const foo: HTMLElement | null до document.querySelector<HTMLElement>("*").
@ Фил Да. и мой ответ кажется вводящим в заблуждение. так что я уже обновил их.
Спасибо, вы имеете в виду, что я утверждаю, что он вернет
HTMLELement(хотя*вполне может соответствоватьSVGElement), и TypeScript этим доволен? Но в сгенерированном JavaScriptquerySelector('*')может вернуть неHTMLElement, а затем доступ к его свойствам, специфичным дляHTMLElement, может привести к ошибке... Я думал, что TypeScript хотя бы предупредит об этом. Я неправильно понимаю?