javascript - TypeScript'te HTMLFormElement'in tekrar tekrar dönüştürülmesini nasıl önlerim


Şu anda bir formun elemanları üzerinde aşağıdaki kodu kullanarak döngü yapıyorum, ancak tekrarlanan as HTMLFormElement dönüşümlerinden nasıl kurtulabileceğimi merak ediyorum. Eğer onları çıkarırsam, Property 'type' does not exist on type 'Element' uyarısı alıyorum.

Array.from((e.target as HTMLFormElement).elements)
  .filter(el => (el as HTMLFormElement).type === 'radio')
  .filter(el => (el as HTMLFormElement).checked === true)

Bir örneği şu şekilde bir Array'e yükseltebilsem de:

const els = Array.from((e.target as HTMLFormElement).elements) as Array<HTMLFormElement>
els
  .filter(el => el.type === 'radio')
  .filter(el => el.checked === true)

Sanki bunu dönüştürmeye gerek kalmadan sadece türünü tanımlayıp/doğrulamam mümkün olmalı.

Bunun eşit derecede iyi çalışmamasının bir nedeni var mı?

const els: Array<HTMLFormElement> = Array.from((e.target as HTMLFormElement).elements

Tam bağlam bir React bileşenidir.

export const Form = ({ children }: FormProps) => {
  const handleSubmit = (e: React.FormEvent<HTMLFormElement>): void => {
    e.preventDefault()

    const els = Array.from((e.target as HTMLFormElement).elements)
    els.filter(el => el instanceof HTMLInputElement && el.type === 'radio' && el.checked === true)
  }

  return (
    <form onSubmit={handleSubmit}>
      {children}
      <br />
      <button type="submit">Submit</button>
    </form>
  )
}

Cevap #1

Tekrar eden iddialar gereksizdir çünkü yalnızca tek bir .filter geri çağrısına ihtiyacınız vardır. Ayrıca, .elements koleksiyonu, girişler ve düğmeler gibi kontrol elemanlarından oluşacaktır - HTMLFormElement değil (bunu yalnızca içeren <form> içerir) - iki as ifadeniz yanlış bir şekilde iddia etmektedir.

Tek tek üzerinde döngü yapılan öğenin bir <input> olup olmadığını JavaScript'te test ederek doğrulamaları tamamen ortadan kaldırabilirsiniz (bu daha güvenlidir).

Array.from((e.target as HTMLFormElement).elements)
    .filter(el => el instanceof HTMLInputElement && el.type === 'radio' && el.checked === true);

Bunun eşit derecede iyi çalışmamasının bir nedeni var mı?

Peki, öncelikle düzgün bir şekilde yazılması gerekir - ama TypeScript'in türü otomatik olarak çıkarmasına izin vermek daha kolay olur (şu anda yaptığı gibi genel bir Element türü yeterlidir) ve düzeltmeye çalışmakla uğraşmamak.

Bu bir olay işleyicisinde gibi görünüyor, dinleyicinin eklendiği element doğru şekilde yazıldıysa, e.target'i dönüştürmek zorunda kalmadan ona tekrar başvurabilirsiniz.

const form = document.querySelector('form')!;
form.addEventListener('submit', () => {
    Array.from(form.elements)
        .filter(el => el instanceof HTMLInputElement && el.type === 'radio' && el.checked);
});

ancak sayfada birden fazla form varsa, genel birine ihtiyacınız olacak

const form = document.querySelector<HTMLFormElement>('form')!;

Elde edilen filtrelenmiş dizinin tiplenmesi gerekiyorsa, tek seçenek, sonuna as Array<HTMLInputElement> ekleyerek ya da .filter metodunu genel (generic) yaparak bir nebze tekrar edici olmaktır.


Eğer bu React ise, daha iyi yaklaşımlar vardır:

  • Olay işleyicisinden .currentTarget öğesini referans göstererek, React dinleyicinin eklenmiş olduğu elementin .currentTarget ile aynı olduğunu, tür dönüştürmeye gerek kalmadan tanıyacaktır:

    const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault()
        const els = Array.from(e.currentTarget.elements)
    

    (Buna karşılık, .target herhangi bir öğe olabilir. .currentTarget genellikle TypeScript ile daha iyi çalışır.)

  • Vanilla DOM manipülasyon yöntemlerinden React'te kaçınılmalıdır. Form elemanından çocuklara erişmek yerine, çocukların durumuna bir durum değişkeninden erişmek daha zarif olur. Kontrol edilen bileşenler genellikle kontrol edilmeyen bileşenlere göre kodu yönetmeyi kolaylaştırır.