microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.24k stars 12.52k forks source link

HTMLCollection should be string indexable #19437

Open akdor1154 opened 7 years ago

akdor1154 commented 7 years ago

According to MDN, HTMLCollection should be string indexable:

HTMLCollection also exposes its members directly as properties by both name and index. HTML IDs may contain : and . as valid characters, which would necessitate using bracket notation for property access. Currently HTMLCollections does not recognize purely numeric IDs, which would cause conflict with the array-style access, though HTML5 does permit these.

TypeScript Version: master

Code

declare const elements: HTMLCollection;
elements['myId'] // implicit any error, where it should be the same type as elements[0].
DanielRosenwasser commented 7 years ago

Is this extremely common? Seems like a potential footgun.

akdor1154 commented 7 years ago

I only really dabble in frontend, but I hit it when trying to use the subclass HTMLFormControlsCollection, where it makes a lot of sense from a user perspective (form.elements['username'], form.elements['password']).

Is this extremely common? Seems like a potential footgun.

Seems you could be talking about JS itself :p

Oaphi commented 3 years ago

To add to the discussion, the presence of a string index on the interface is defined by the DOM standard (as a named property getter). Since the interface is still widely used (as methods getElementsByClassName and getElementsByTagName return HTMLCollections of elements), it would make sense to support string indexing.

Also, being able to access elements by id/name allows for the use of destructuring assignment with objects:

interface HTMLCollectionOf<T extends Element> {
    [id:string]: T | undefined
}

const { forms: { form1, form2 } } = document;

as well as use computed property names to access form inputs. A bit contrived example to illustrate the use case:

//HTMLCollectionOf same as above

const myFormPrefix = "wpforms-form";

const formIds = [330, 340, 350];

const { forms } = document;
const wpfs = formIds.map((id) => forms[`${myFormPrefix}-${id}`]);
jbalsas commented 3 years ago

Not sure how common this is (likely not much since this is open for years with little activity), but I just ran into this when migrating some legacy codebase in the form of:

function getFormElement(form: HTMLFormElement, elementName: string) {
    return form.elements[elementName]; // Element implicitly has an 'any' type because index expression is not of type 'number'.
}
esperecyan commented 1 month ago

It should be handled the same way as HTMLFormElement. Accessing it via something like document.forms.formName is a common usage pattern.