镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

'window.location' should allow assigning a string #48949

Open

Description

@fcole90

Bug Report

🔎 Search Terms

window.location, location.href

🕗 Version & Regression Information

  • No version has the behaviour I'd expect, however up to version 4.5.5 windows.location is of type Location, while from version 4.6.2 is of type (string | Location) & Location. FAQ do not mention anything about it.

⏯ Playground Link

Playground link with relevant code

💻 Code

window.location = "https://github.com/";

🙁 Actual behavior

window.location = "https://github.com/";
// (property) location: (string | Location) & Location
// Type 'string' is not assignable to type '(string | Location) & Location'.(2322)

While it's true that Location is an object and not a string, assigning a string to it is a long-established and recommended pattern, that may produce a different result from window.location.href = "https://github.com/";.

Example of where assigning a string to window.location is the correct behaviour: https://javascript.info/cross-window-communication#4q5rssu5ys

Also, according to MDN:

Though Window.location is a read-only Location object, you can also assign a DOMString to it. This means that you can work with location as if it were a string in most cases: location = 'http://www.example.com' is a synonym of location.href = 'http://www.example.com'.

Further discussion on difference between assigning to location or to location.href: https://stackoverflow.com/questions/2383401/javascript-setting-location-href-versus-location

🙂 Expected behavior

window.location = "https://github.com/";
// (property) location: string | Location
// No error

Mock playground

I could not find the rationale behind the change that happened between 4.5.5 and 4.6.2, that changed its type from Location to (string | Location) & Location, but I wonder if the intended result was the same I'm expecting here.

Activity

  1. fcole90 commented on May 4, 2022

    @fcole90
    Author

    I think this might be the relevant code:

    set location(href: string | Location);

  2. changed the title [-]Typing likely wrong for 'window.location'[/-] [+]'window.location' should allow assigning a string[/+] on May 4, 2022
  3. MartinJohns commented on May 4, 2022

    @MartinJohns
    Contributor

    The issue is that window is typed Window & typeof globalThis (intentional), and that (typeof globalThis)['location'] is typed Location, not Location | string. I'm not sure where globalThis is defined.

    As a workaround you can do:

    const win: Window = window;
    win.location = "https://github.com/";
  4. andrewbranch commented on May 4, 2022

    @andrewbranch
    Member

    globalThis is all the globals, and there’s declare var location: Location elsewhere in lib.dom.d.ts. I guess this is intended to reflect the combination of

    1. Everything on window can be accessed as a global
    2. Every global (even ones you declare in your own code) can be accessed on window
    3. Not every Window is window

    It’s a bummer because (2) has always been super weird to me and I wouldn’t have minded if TypeScript didn’t reflect that behavior, which would have meant the type of window would just be Window. As it is, I don’t know that we have any mechanism to make this work 😕

  5. added
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.
    RevisitAn issue worth coming back to
    on May 4, 2022
  6. fatcerberus commented on May 4, 2022

    @fatcerberus

    (2) has always been super weird to me

    Indeed it is, but that's just a side effect of the fact that window === globalThis, similar to how global === globalThis in Node (globalThis having been added specifically to standardize the name of the global object across environments). Just more legacy baggage we're stuck with from the earliest days of JS, like typeof null === 'object' 😞

  7. fcole90 commented on May 6, 2022

    @fcole90
    Author

    The issue is that window is typed Window & typeof globalThis (intentional), and that (typeof globalThis)['location'] is typed Location, not Location | string. I'm not sure where globalThis is defined.

    As a workaround you can do:

    const win: Window = window;
    win.location = "https://github.com/";

    Could we perhaps just fix this by changing the type of globalThis.location in the same way? Or am I missing anything?

  8. fcole90 commented on May 6, 2022

    @fcole90
    Author

    Is it perhaps this the line where the location provided by globalThis is defined?

    declare var location: Location;

    Or is it just one more place?

  9. andrewbranch commented on May 6, 2022

    @andrewbranch
    Member

    That’s the line, but the problem is that it’s a global variable, not a property. If it were declared as a property like it is on Window, you could change it to a get/set accessor pair with different types. But there’s no way to say that a declare var has a different write type from its read type.

  10. fcole90 commented on May 6, 2022

    @fcole90
    Author

    Mmh, I see, so if we did

    declare var location: Location | string;

    it would be wrong anyway as location cannot be of type string 🤔

    Are there other situations you're aware of where a global variable might need to be defined in different ways between get/set?

  11. fatcerberus commented on May 6, 2022

    @fatcerberus

    It’s technically not a wrong type even then, but you wouldn't be able to access properties of Location on it without a cast or a useless type guard, since TS would think it might be a string.

  12. andrewbranch commented on May 6, 2022

    @andrewbranch
    Member

    Are there other situations you're aware of where a global variable might need to be defined in different ways between get/set?

    I’m actually not sure whether this is possible outside of window. My hot take is that maybe instead of declaring all these globals and then calling window Window & typeof globalThis, there should have been a dedicated way to declare that window is an alias of globalThis, and all its properties would be accessible without qualification, while global variables would still appear as properties on it like they do now. Then you could delete all the declare vars that are essentially duplicates of Window properties. There could be some huge pitfall that I’m not thinking of since I’ve only been thinking about it for 30 seconds.

  13. fabio-colella-md commented on Jun 8, 2022

    @fabio-colella-md

    Hi, any update on this? 😊

  14. KKrisu commented on Aug 3, 2022

    @KKrisu

    (window as Window).location = 'abc' ✔️

  15. el1s7 commented on Sep 20, 2022

    @el1s7

    Typescript is full of annying shit like this, just do

    //@ts-ignore
    window.location = '/'
    
  16. aradalvand commented on Jul 5, 2023

    @aradalvand

    This should've honestly been fixed already.

  17. adampl commented on Jul 18, 2023

    @adampl

    There's also the window.location.assign(url) method that does exactly the same thing.

  18. Tanaykmr commented on Jan 30, 2024

    @Tanaykmr

    Is there any update on this?

  19. Rinzwind commented on Feb 27, 2024

    @Rinzwind

    There's also the window.location.assign(url) method that does exactly the same thing.

    Note that it is not equivalent in the case of differing origins. In the following example, buttons 1 and 2 change the location of the frame, but button 3 causes an exception (“Blocked a frame with origin "null" from accessing a cross-origin frame”). See the documentation on Location.href and Location.assign() in the MDN Web Docs.

    <html><body>
    	<iframe name="f" src="https://www.wikipedia.org"></iframe><br>
    	<button onclick="window.frames.f.location = 'https://www.wiktionary.org'">1</button>
    	<button onclick="window.frames.f.location.href = 'https://www.wiktionary.org'">2</button>
    	<button onclick="window.frames.f.location.assign('https://www.wiktionary.org')">3</button>
    </body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.RevisitAn issue worth coming back to

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions