Skip to content
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

Root scope type #10050

Closed
nin-jin opened this issue Jul 31, 2016 · 8 comments
Closed

Root scope type #10050

nin-jin opened this issue Jul 31, 2016 · 8 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@nin-jin
Copy link

nin-jin commented Jul 31, 2016

TypeScript Version: 1.8.10

Code

class XXX {
    static say() { alert( 'Good!' ) }
}

var win : Window = this

win.XXX.say()

Expected behavior:

No errors.

Actual behavior:

Error: Property 'XXX' does not exist on type 'Window'.

Code

class XXX {}

var glob = this

glob.XXX.broken()

Expected behavior:

Error: Property 'broken' does not exist on type 'XXX'.

Actual behavior:

No type checks.

@nin-jin
Copy link
Author

nin-jin commented Jul 31, 2016

Workaround - manual add all defined classes/functions/variables to Window interface.

class XXX {
    static say() { alert( 'Good!' ) }
}

var win : Window = this

interface Window {
    XXX : typeof XXX
}

win.XXX.say()

@nin-jin
Copy link
Author

nin-jin commented Jul 31, 2016

Suggestion: automatic register all global entities in Global interface.

class XXX {}
function YYY { return ZZZ }
var ZZZ = this // "this" has type "Global"

var xxx = new (win.ZZZ.ZZZ.YYY().XXX) // Returns "XXX" type

@nin-jin
Copy link
Author

nin-jin commented Jul 31, 2016

Why i need this

For mocking.

function myAlert( message : string ) {
    alert( message )
}
class XXX {
    $ = window
    run( ) {
        this.$.myAlert( 'hello' )
    }
}
var alertedMessage
var xxx = new XXX
xxx.$ = Object.assign( Object.create( this ) , {
    myAlert : message => alertedMessage = message
} )
xxx.run()
console.assert( alertedMessage === 'hello' )

For overriding classes in runtime component tree.

@yortus
Copy link
Contributor

yortus commented Aug 1, 2016

I agree that globals are more painful to model than non-globals. Both lib.d.ts and node.d.ts currently require a large number of duplicate definitions to keep their Window and Global types synchronised with their global declarations, and these duplicates must be manually kept in sync (thankfully they don't change often).

So there is, for example, both interface Window { onload: (this: this, ev: Event) => any; } as well as declare var onload: (this: Window, ev: Event) => any; in lib.d.ts, and dozens or hundreds more duplicates like that.

I have a project where scripts can be run in a sandbox, and I'd like to tell TypeScript to type-check those scripts using the definitions in, say, interface SandboxGlobals { foo: string; bar; number; } as the global object. That way, the host code sees SandboxGlobals as just an ordinary type, and can do something like var g = new SandboxGlobals(). But the sandboxed code sees SandboxGlobals as the global object, with foo and bar as globals. Currently I need to maintain duplicate definitions, similar to the way lib.d.ts does, to achieve this.

Suppose there was a way to tell the compiler "this declaration's members are also globals", something like declare global extends Window;, or Window is global; or whatever. That could do away with the duplicate definitions in Window and Global, and also solve my project problem, and also permit the expected behaviour posed by the OP here.

@mhegazy
Copy link
Contributor

mhegazy commented Aug 25, 2016

This has been an intentional design choice for TypeScript. global pollution, though common, are not considered to be a good practice. the global object is different based on the engine/host implementation, e.g. window, self, global, etc.. even the value of this had different meaning at the global scope between node and the browser.
The language allows for declaration merging which handles this scenario. And i would argue this approach rationalizes how things should be accesses either through a global, this, window, or a local. I do not believe there is much value if enabling automatic global scope pollution.

@mhegazy mhegazy added the Working as Intended The behavior described is the intended behavior; this is not a bug label Aug 25, 2016
@nin-jin
Copy link
Author

nin-jin commented Aug 26, 2016

global pollution, though common, are not considered to be a good practice

This is normal practice. Tools must support this and should not impose any doctrine.

value of this had different meaning at the global scope between node and the browser.

Yes, this is a problem. Workaround:

var glob : Global = (function(){ return this })()

@saschanaz
Copy link
Contributor

saschanaz commented Aug 26, 2016

Will the situation change when System.global stage 2 proposal completes?

@mhegazy
Copy link
Contributor

mhegazy commented Aug 26, 2016

This is normal practice. Tools must support this and should not impose any doctrine.

TypeScript does support this. first this in the global scope has type any, so you can access anything on this. and the Window interface is augmantable to add whatever declarations you so choose. this is the intended design.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants