microsoft / TypeScript

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

HTMLFormElement disallows symbol keys #58305

Closed miss-programgamer closed 2 weeks ago

miss-programgamer commented 3 weeks ago

⚙ Compilation target

ESNext

⚙ Library

None

Missing / Incorrect Definition

HTMLFormElement erroneously does not allow symbols to be used as keys. This is presumably because its interface declaration in lib.dom.d.ts explicitly defines numeric keys and string keys, but no symbol keys.

Sample Code

const symbol = Symbol();
const form = document.getElementById('search') as HTMLFormElement;
form[symbol] = "Something";

Documentation Link

No response

RyanCavanaugh commented 3 weeks ago

This isn't really any different from writing

form.blah = 42;

which is disallowed for similar reasons. It's expected to use a type assertion or interface merge if you're doing this on purpose.

miss-programgamer commented 3 weeks ago

Then I have the inverse problem to report, which is that every other type which is/derives from HTMLElement allows the use of symbol keys in the way I showed.

nmain commented 3 weeks ago

@miss-programgamer That doesn't seem to be the case: Playground. Can you show a reproduction of this?

declare var a: HTMLSpanElement;
declare var b: symbol;
declare var c: any;

a[b] = c; // Element implicitly has an 'any' type because expression of type 'symbol' can't be used to index type 'HTMLSpanElement'.(7053)
whzx5byb commented 3 weeks ago

@nmain set noImplicitAny=false and you will see the different behavior between HTMLFormElement and HTMLSpanElement. I believe it is caused by the signature [name: string]: any; in the interface HTMLFormElement but I don't know why.

typescript-bot commented 2 weeks ago

This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

miss-programgamer commented 2 weeks ago

This is definitely not working as intended. The entire point of symbols is that you can use them as keys on any object to attach things to them anonymously, I shouldn't have to define an interface merge just to account for the fact that the interface for one html element defines string keys to any. I use them to attach component instances to the root elements of those components, and I think that's a perfectly normal use case. Even on principle I don't see why typescript should disallow this by default. Symbol keys just aren't the same as string or number keys, and really shouldn't be treated the same as far as interfaces are concerned.

And even if you disagree with me, I've still pointed out that there's an inconsistency in the interfaces of html elements, so you should at least deliberate on how to make the behaviour consistent between element types, regardless of how you choose to resolve this. And no, arguing that this only happens when using implicit any isn't cause to dismiss this issue.