3

The following error appears when trying to destructure a form.elements object:

Type 'HTMLFormControlsCollection' has no property 'x' and no string index signature

// in a class

domRefs: {[key: string]: HTMLFormElement | null} = {
  myForm: null
}

onButtonClick = () => {
  console.debug(this.domRefs.myForm!.elements) // screenshot below
  const {a, b, c} = this.domRefs.myForm!.elements
}

screenshot of the console output

I don't want to use the : any type annotation that does not emit this error.

Qwerty
  • 29,062
  • 22
  • 108
  • 136
  • I am sure you already solved it long time ago - but just for the benefit of other readers - as usual, the culprit is a limitation of the standard definition library, nothing else one can do apart from augmenting the `HTMLFormControlsCollection` interface. – Oleg Valter is with Ukraine May 23 '21 at 17:00

2 Answers2

1

This is a limitation of the standard DOM definitions library (and still is in 2021). Here is how the HTMLFormControlsCollection is defined in it - notice the lack of a string index signature (this is exactly why the error happens):

interface HTMLFormControlsCollection extends HTMLCollectionBase {
    /**
     * Returns the item with ID or name name from the collection.
     * 
     * If there are multiple matching items, then a RadioNodeList object containing all those elements is returned.
     */
    namedItem(name: string): RadioNodeList | Element | null;
}

Its parent interface HTMLCollectionBase also lacks a string index signature (despite having a number index signature):

interface HTMLCollectionBase {
    /**
     * Sets or retrieves the number of objects in a collection.
     */
    readonly length: number;
    /**
     * Retrieves an object from various collections.
     */
    item(index: number): Element | null;
    [index: number]: Element;
}

However, HTMLFormControlsCollection should have a string index signature by definition (see the standard):

element = collection[name]
radioNodeList = collection[name]
Returns the item with ID or name name from the collection.

So, with the help of some declaration merging, we can fix the omission:

interface HTMLFormControlsCollection extends HTMLCollectionBase {
  [item: string]: Element | RadioNodeList;
}
  • This gives me `Property 'item' of type '(index: number) => Element | null' is not assignable to 'string' index type 'Element | RadioNodeList'.` in TS 4.7. Is there any newer approach? – Jakub Kotrs Oct 28 '22 at 21:41
  • @JakubKotrs can you share a reproducible example from the Playground, if possible? – Oleg Valter is with Ukraine Oct 28 '22 at 22:10
  • No, it works here, https://www.typescriptlang.org/play?ts=4.7.4#code/JYOwLgpgTgZghgYwgAgBIBUCyAZAYgeygFsBhfcKfAGwGcyqqIExhzkIAPSEAExrSzZ6jZqxAAhODRQBvAFDJkAbWCQiALmQ0wUUAHMAupoCijIhHDIAPsgBKcHqwBy+HhGzBtAbjkBfIA, but as soon as I copy to VSCode, it's all red with TS 4.7.2 :( – Jakub Kotrs Oct 29 '22 at 21:43
  • @JakubKotrs hmm, strange. Can you share the tsconfig file of the project where this happens? I can try a loxal install of 4.7.2 and see for myself if it errors out. – Oleg Valter is with Ukraine Oct 29 '22 at 22:11
  • Thank you very much for the time you're putting into this, I appreciate it a lot! Here is a gist: https://gist.github.com/Goues/1174583df3550d92ee0c8195e082c28c – Jakub Kotrs Oct 31 '22 at 21:17
  • I see same error as @JakubKotrs in VSCode.. – hallvors Jul 07 '23 at 11:24
0

As described by @oleg-valter-is-with-ukraine,

interface HTMLFormControlsCollection extends HTMLCollectionBase {
  [item: string]: HTMLInputElement | RadioNodeList;
}

It worked for me I just changed the Element to HTMLInputElement in the lib.dom.d.ts file

  • 2
    You should not be changing anything in `node_modules`. This change is only for you and not persistent. This means, whenever you or somebody else (re)installs your repo, those changes would get overwritten. Changing something in `node_modules` is good for testing. You can then make [type overrides _(link)_](https://stackoverflow.com/a/55032655/985454) in your [`global.d.ts` _(link)_](https://stackoverflow.com/a/73389225/985454) files inside your `src` project folder or you can make PR in the 3rd party repo. – Qwerty Jul 04 '23 at 03:57
  • 1
    @Qwerty, thankyou I will keep that in my mind and will rectify the mistake – Karan Badhwar Jul 04 '23 at 17:58