Использование querySelector в Typescript: почему он принимает возвращаемый тип HTMLElement?

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?

Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
0
52
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Сигнатура метода

querySelector<E extends Element = Element>(selectors: string): E | null;

Определив возвращаемый тип как HTMLElement (см. Вывод типа), вы предоставили общий тип E. Ваш код эквивалентен

const foo = document.querySelector<HTMLElement>('*'); // HTMLElement | null

Единственное ограничение состоит в том, что E должно расширяться Element.

Спасибо, вы имеете в виду, что я утверждаю, что он вернет HTMLELement (хотя * вполне может соответствовать SVGElement), и TypeScript этим доволен? Но в сгенерированном JavaScript querySelector('*') может вернуть не HTMLElement, а затем доступ к его свойствам, специфичным для HTMLElement, может привести к ошибке... Я думал, что TypeScript хотя бы предупредит об этом. Я неправильно понимаю?

Aayla Secura 04.09.2024 09:04

Это верно. Это один из тех случаев, когда вы, по сути, говорите компилятору, что вы знаете лучше всех. Однако это не предотвратит проблемы во время выполнения.

Phil 04.09.2024 09:05

В машинописном тексте нет ничего плохого. Из 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>("*").

@ Фил Да. и мой ответ кажется вводящим в заблуждение. так что я уже обновил их.

Jakkapong Rattananen 04.09.2024 11:19

Другие вопросы по теме

Похожие вопросы

Есть ли способ отключить утверждения скриншотов в драматурге?
Вывод типа для значения параметра автозаполнения перегруженного метода
Можно ли заставить TypeScript понять следующее назначение общего объекта?
Тип переменной Typescript не меняется даже при строго типизированных манипуляциях
Почему функции Contravariance с их параметрами в машинописном тексте?
Получите доступ к этому в функции, которая является свойством объекта
Создание сопоставлений на основе перечислений, включая обеспечение ошибок компилятора
Почему сопоставление массива не работает с той же записью сопоставления рекламы?
React Router обнаружил следующую ошибку во время рендеринга. Ошибка: отрисовано меньше перехватчиков, чем ожидалось
Почему машинописный текст не позволяет частично указывать аргументы типа, чтобы создать новую универсальную функцию из другой универсальной функции?