visual studio code - TypeScript neden document.getElementById() sonucunda style özelliğini öneriyor, ama document.querySelector() için önermiyor?


Ben "document.querySelector()." yazıp önerileri tetiklemek için CTRL+Spacebar tuşlarına bastığımda, style özelliği önerilmiyor, ancak document.getElementById() ile sorunsuz çalışıyor gibi görünüyor.

Bu neden oluyor ve bunu nasıl düzeltirim?

querySelector ile:

getElementById ile:

IntelliSense'in 'document.querySelector().' ile 'style' özelliğini önermesini bekliyordum, ama önermedi. Neden?

Cevap #1

Eğer acele ediyorsanız ve 'neden' umursamıyorsanız, 'çözüm' için bu yazının sonuna atlayın

Bu ilginç. DOM standardına göre, hem querySelector hem de getElementById, ya bir Element örneği döner ya da null.

Belgeler :

  • https://dom.spec.whatwg.org/#ref-for-dom-parentnode-queryselector%E2%91%A0
  • https://dom.spec.whatwg.org/#ref-for-dom-nonelementparentnode-getelementbyid%E2%91%A1

Ancak, lib.dom.ts içinde, querySelector için dönüş tipi Element | null olarak belirtildi ve HTML belgeleri için getElementById dönüş tipi HTMLElement | null olarak tanımlandı. Ve style DOM özelliği HTMLElement üzerinde tanımlı, fakat Element üzerinde değil. Burada bir nüans var; querySelector için tip tanımlamaları, sadece standart etiket adları olan seçicileri algılayan ve bu durumları özelleştirip karşılık gelen tipi döndüren aşırı yüklemelere de sahiptir.

Bu zaten TypeScript GitHub deposunun sorun izleyicisinde burada gündeme getirildi: Document.getElementById() HTMLElement değil, Element döndürmelidir #19549, bu tartışmayı Node.parentElement HTMLElement değil, Element olmalı #4689 konusuna taşımak için kapatıldı. Tartışmayı orada takip edebilirsiniz. İşte konuyla ilgili bakımcıların bazı düşünceleri:

Bu tartışmalıdır, çünkü daha önce bir şikayet vardı; çoğu durumda gerçek tip HTMLElement olmasına rağmen, her zaman Element tipini HTMLElement tipine dönüştürmenin çok zahmetli olduğu söylendi, spec her ne kadar Element olması gerektiğini belirtse de.

Örneğin, getElementById metodunun dönüş tipi Element olarak tanımlanmıştır, ancak çok fazla tip dönüşümünden kaçınmak için bunu HTMLElement yaptık. Eğer tip başka bir Element ise, önce onu Element olarak dönüştürebilir ve ardından son tipe çevirebilirsiniz. Çoğu durumda parentElement de HTMLElement olacağı için, onu olduğu gibi bırakmak daha iyi olabilir.

- zhengbli

@jun-sheaf bu değişiklikler için bir PR gönderdi ve bunun 4.1'e dahil edilip edilmeyeceğini incelemekteyim.

Bence bu değişiklikleri yapmamalıyız, çünkü bu, insanların kendi avantajlarına olduğunu düşünmeyecekleri şekilde birçok kodu bozacak. TS, doğruluk ve üretkenliği dengelemeye çalışıyor ve bence getElementById'in, bugün çoğu durumda sahip olduğumuz araç desteğini almak için tür dönüşümü yapılması gereken kodu döndürmeye başlaması (örneğin JS bağlamında HTML düğümleri) TypeScript için kötü bir karar olacak.

[...]

Öte yandan, bunu getElementById<E extends Element=HTMLElement>(elementId: string): E | null olarak değiştirmek, nadir durumlar için dönüş türünü daha az radikal yollarla belirlemeye hâlâ izin verir:

const logo2 = getElementById2("my-logo") as SVGPathElement
const logo3 = getElementById2<SVGPathElement>("my-logo")

Ama varsayılan JS araç desteğini engellemez.

- orta

Bu konu, bu commit ile tamamlanmış olarak kapatıldı: d561e08, ki bu temel olarak orta'nın getElementById için bahsettiği şeyi yaptı. Yani, doğru anladıysam HTML belgeleri için hâlâ HTMLElement döndürüyor (ama SVG veya XML gibi diğer belge türleri için değil).

Başka bir deyişle, işler TypeScript bakımcılarının işlev görmesi için yazdığı şekilde işliyor.

Eğer style özelliğinin querySelector sonucunda kullanılabilir olmasını istiyorsanız, onu bir tür beyanı ile HTMLElement olarak tür dönüştürün (örneğin as HTMLElement ile), veya bir JSDoc açıklaması ile (/**@type{HTMLElement}*/const e=document.querySelector(...); e.style;), veya çalışma zamanında tür kontrolü yapın (if (foo instanceof HTML...Element) {...}), ya da querySelector fonksiyonunun genel parametresini kullanın.

İlgili makaleler