Skip to content

unexpected return type when calling document.querySelector with a non string type argument #10518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
goser opened this issue Aug 24, 2016 · 11 comments
Labels
Duplicate An existing issue was already created

Comments

@goser
Copy link

goser commented Aug 24, 2016

TypeScript Version: v2.0.0-beta

Code

<HTMLDivElement>document.querySelector(<any>'div');

Expected behavior:

  1. Get "Element" as return type like in previous versions.
    or
  2. Get an error for not using a string as argument.

Actual behavior:
Compiler outputs following error:
test.ts(1,1): error TS2352: Type 'HTMLAnchorElement' cannot be converted to type 'HTMLDivElement'.
Property 'align' is missing in type 'HTMLAnchorElement'.

I think this has something to do with the changes for #8114.

@kitsonk
Copy link
Contributor

kitsonk commented Aug 24, 2016

Why are you coercing a string literal ('div') into an any?

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label Aug 24, 2016
@mhegazy
Copy link
Contributor

mhegazy commented Aug 24, 2016

querySelector is defined with a set of overloads, the relevant ones are:

querySelector(selectors: "div"): HTMLDivElement;
querySelector(selectors: "a"): HTMLAnchorElement;
....
querySelector(selectors: string): Element;
....

this tells the compiler if the argument is the literal type `"div"` the result is an HTMLDivElement, if the argument is or type `"a"` HTMLAnchorElement is returned and so on.. otherwise, if no specific tag can be determined the general element type would be provided.

so all these would result in picking the desired signature.

var d = document.querySelector('div'); // HTMLDivElement

const DivTagName: "div" = "div";
var d = document.querySelector(DivTagName); // HTMLDivElement

var d = document.querySelector(<"div">someString); // HTMLDivElement

otherwise, you will need to cast the output to the desired element type:

var d = <HTMLDivElement>document.querySelector(someString);

@mhegazy mhegazy closed this as completed Aug 24, 2016
@Arnavion
Copy link
Contributor

any is allowed to match a string literal overload, so it's matching the first overload of querySelectorAll instead of the last string one. It does seem odd, but it also makes sense given that string literals are types as well.

@RyanCavanaugh RyanCavanaugh reopened this Aug 24, 2016
@RyanCavanaugh RyanCavanaugh removed the Question An issue which isn't directly actionable in code label Aug 24, 2016
@RyanCavanaugh
Copy link
Member

Returning an HTMLAnchorElement is super weird, though, and this is a breaking change. We should figure out some sort of fix.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 24, 2016

but it is a regular type now and not a specialized signature. i do not see why we should treat them any different..

@kitsonk
Copy link
Contributor

kitsonk commented Aug 24, 2016

But should there be an order of precedence? When matching against any shouldn't it choose the widest? Therefore:

querySelector(selectors: string): Element;

Instead of "randomly" selecting something.

@RyanCavanaugh
Copy link
Member

Logged #10523

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Aug 24, 2016
@mhegazy
Copy link
Contributor

mhegazy commented Aug 24, 2016

doing some digging, this behavior has been there in 1.8 (see createElement), the issue is the change to the querySelector and querySelectorAll overloads happened in TS 2.0.

Instead of "randomly" selecting something.

it is not really random. overload resolution is order sensitive, it picks the first signature that matches, which happens to be the HTMLAnchorElement.

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 24, 2016

It's random to the user. We could have put those overloads in literally any order. There's no reason to expect HTMLAnchorElement any more than HTMLBaseFontElement.

@kitsonk
Copy link
Contributor

kitsonk commented Aug 25, 2016

Yes, which why I used "randomly" (quotes denoting perception versus reality) knowing it wasn't left up to actual chance, but to arbitrariness, which is what led to my other comment in #10523 which was that sometimes ordering of interfaces cannot be easily controlled when there is interface merging going on. There is no way of ensuring that overrides of your interfaces are ordered properly.

@goser
Copy link
Author

goser commented Aug 25, 2016

@kitsonk I tried to use array elements as selectors. But I forgot to set the array type. :)

It is not a real problem for me but getting a HTMLAnchorElement feels strange.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants