diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index c7d258bb1d919..384538418c7d8 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2364,7 +2364,13 @@ namespace ts { break; case SyntaxKind.SourceFile: // this.foo assignment in a source file - // Do not bind. It would be nice to support this someday though. + // Bind this property in the global namespace or in the exports if in commonjs + if ((thisContainer as SourceFile).commonJsModuleIndicator) { + declareSymbol(thisContainer.symbol.exports, thisContainer.symbol, node, SymbolFlags.Property | SymbolFlags.ExportValue, SymbolFlags.None); + } + else { + declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes); + } break; default: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cc17e30e0e098..37f6e886b50cb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -419,6 +419,7 @@ namespace ts { let deferredGlobalAsyncIteratorType: GenericType; let deferredGlobalAsyncIterableIteratorType: GenericType; let deferredGlobalTemplateStringsArrayType: ObjectType; + let deferredGlobalGlobalType: ObjectType; let deferredNodes: Node[]; let deferredUnusedIdentifierNodes: Node[]; @@ -7612,6 +7613,10 @@ namespace ts { return deferredGlobalIterableIteratorType || (deferredGlobalIterableIteratorType = getGlobalType("IterableIterator" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; } + function getGlobalGlobalType() { + return deferredGlobalGlobalType || (deferredGlobalGlobalType = createAnonymousType(undefined, globals, emptyArray, emptyArray, createIndexInfo(anyType, /*isReadonly*/ false), undefined)) || emptyObjectType; + } + function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType { const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined); return symbol && getTypeOfGlobalSymbol(symbol, arity); @@ -13960,6 +13965,16 @@ namespace ts { if (type && type !== unknownType) { return getFlowTypeOfReference(node, type); } + if (isSourceFile(container)) { + // look up in the source file's locals or exports + if (container.commonJsModuleIndicator) { + const fileSymbol = getSymbolOfNode(container); + return fileSymbol && getTypeOfSymbol(fileSymbol); + } + else { + return getGlobalGlobalType(); + } + } } } diff --git a/tests/baselines/reference/topLevelThisAssignment.errors.txt b/tests/baselines/reference/topLevelThisAssignment.errors.txt new file mode 100644 index 0000000000000..a24f51f7fbd32 --- /dev/null +++ b/tests/baselines/reference/topLevelThisAssignment.errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/salsa/a.js(4,1): error TS2304: Cannot find name 'unknown'. +tests/cases/conformance/salsa/b.js(3,1): error TS2304: Cannot find name 'unknown'. + + +==== tests/cases/conformance/salsa/a.js (1 errors) ==== + this.a = 10; + this.a; + a; + unknown; + ~~~~~~~ +!!! error TS2304: Cannot find name 'unknown'. + this.unknown; + + // also, improved types for this-prefixed globals like eval: + this.eval('hi'); + +==== tests/cases/conformance/salsa/b.js (1 errors) ==== + this.a; + a; + unknown; + ~~~~~~~ +!!! error TS2304: Cannot find name 'unknown'. + this.unknown; + \ No newline at end of file diff --git a/tests/baselines/reference/topLevelThisAssignment.js b/tests/baselines/reference/topLevelThisAssignment.js index c87fad289f709..55e5342e33361 100644 --- a/tests/baselines/reference/topLevelThisAssignment.js +++ b/tests/baselines/reference/topLevelThisAssignment.js @@ -4,15 +4,28 @@ this.a = 10; this.a; a; +unknown; +this.unknown; + +// also, improved types for this-prefixed globals like eval: +this.eval('hi'); //// [b.js] this.a; a; +unknown; +this.unknown; //// [output.js] this.a = 10; this.a; a; +unknown; +this.unknown; +// also, improved types for this-prefixed globals like eval: +this.eval('hi'); this.a; a; +unknown; +this.unknown; diff --git a/tests/baselines/reference/topLevelThisAssignment.symbols b/tests/baselines/reference/topLevelThisAssignment.symbols index e9b94983bf287..dd3ba31d2bf04 100644 --- a/tests/baselines/reference/topLevelThisAssignment.symbols +++ b/tests/baselines/reference/topLevelThisAssignment.symbols @@ -1,10 +1,31 @@ === tests/cases/conformance/salsa/a.js === this.a = 10; -No type information for this code.this.a; -No type information for this code.a; -No type information for this code. -No type information for this code.=== tests/cases/conformance/salsa/b.js === +>this.a : Symbol(a, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(a.js, 0, 0)) + this.a; -No type information for this code.a; -No type information for this code. -No type information for this code. \ No newline at end of file +>this.a : Symbol(a, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(a.js, 0, 0)) + +a; +>a : Symbol(a, Decl(a.js, 0, 0)) + +unknown; +this.unknown; + +// also, improved types for this-prefixed globals like eval: +this.eval('hi'); +>this.eval : Symbol(eval, Decl(lib.d.ts, --, --)) +>eval : Symbol(eval, Decl(lib.d.ts, --, --)) + +=== tests/cases/conformance/salsa/b.js === +this.a; +>this.a : Symbol(a, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(a.js, 0, 0)) + +a; +>a : Symbol(a, Decl(a.js, 0, 0)) + +unknown; +this.unknown; + diff --git a/tests/baselines/reference/topLevelThisAssignment.types b/tests/baselines/reference/topLevelThisAssignment.types index 024c360f8ccd6..45cc6416fc8ed 100644 --- a/tests/baselines/reference/topLevelThisAssignment.types +++ b/tests/baselines/reference/topLevelThisAssignment.types @@ -1,25 +1,49 @@ === tests/cases/conformance/salsa/a.js === this.a = 10; >this.a = 10 : 10 ->this.a : any ->this : any ->a : any +>this.a : number +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; a: number; undefined: undefined; } +>a : number >10 : 10 this.a; ->this.a : any ->this : any ->a : any +>this.a : number +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; a: number; undefined: undefined; } +>a : number a; ->a : any +>a : number + +unknown; +>unknown : any + +this.unknown; +>this.unknown : any +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; a: number; undefined: undefined; } +>unknown : any + +// also, improved types for this-prefixed globals like eval: +this.eval('hi'); +>this.eval('hi') : any +>this.eval : (x: string) => any +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; a: number; undefined: undefined; } +>eval : (x: string) => any +>'hi' : "hi" === tests/cases/conformance/salsa/b.js === this.a; ->this.a : any ->this : any ->a : any +>this.a : number +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; a: number; undefined: undefined; } +>a : number a; ->a : any +>a : number + +unknown; +>unknown : any + +this.unknown; +>this.unknown : any +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; a: number; undefined: undefined; } +>unknown : any diff --git a/tests/baselines/reference/topLevelThisAssignment2.errors.txt b/tests/baselines/reference/topLevelThisAssignment2.errors.txt new file mode 100644 index 0000000000000..c4e372eab82bd --- /dev/null +++ b/tests/baselines/reference/topLevelThisAssignment2.errors.txt @@ -0,0 +1,20 @@ +tests/cases/conformance/salsa/mod.js(6,1): error TS2304: Cannot find name 'a'. + + +==== tests/cases/conformance/salsa/use.js (0 errors) ==== + var mod = require('./mod') + mod.a; + +==== tests/cases/conformance/salsa/decl.d.ts (0 errors) ==== + declare var module: { exports: any }; + declare function require(name: string): any; +==== tests/cases/conformance/salsa/mod.js (1 errors) ==== + /// + module.exports = {}; + this.a = 10; + this.a; // ok + module.exports.a; // should be ok but doesn't have the right type + a; // error: not actually at top-level in a module + ~ +!!! error TS2304: Cannot find name 'a'. + \ No newline at end of file diff --git a/tests/baselines/reference/topLevelThisAssignment2.symbols b/tests/baselines/reference/topLevelThisAssignment2.symbols new file mode 100644 index 0000000000000..6f0eded03efdb --- /dev/null +++ b/tests/baselines/reference/topLevelThisAssignment2.symbols @@ -0,0 +1,44 @@ +=== tests/cases/conformance/salsa/use.js === +var mod = require('./mod') +>mod : Symbol(mod, Decl(use.js, 0, 3)) +>require : Symbol(require, Decl(decl.d.ts, 0, 37)) +>'./mod' : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0)) + +mod.a; +>mod.a : Symbol(a, Decl(mod.js, 1, 20)) +>mod : Symbol(mod, Decl(use.js, 0, 3)) +>a : Symbol(a, Decl(mod.js, 1, 20)) + +=== tests/cases/conformance/salsa/decl.d.ts === +declare var module: { exports: any }; +>module : Symbol(module, Decl(decl.d.ts, 0, 11)) +>exports : Symbol(exports, Decl(decl.d.ts, 0, 21)) + +declare function require(name: string): any; +>require : Symbol(require, Decl(decl.d.ts, 0, 37)) +>name : Symbol(name, Decl(decl.d.ts, 1, 25)) + +=== tests/cases/conformance/salsa/mod.js === +/// +module.exports = {}; +>module.exports : Symbol(exports, Decl(decl.d.ts, 0, 21)) +>module : Symbol(module, Decl(decl.d.ts, 0, 11)) +>exports : Symbol(exports, Decl(decl.d.ts, 0, 21)) + +this.a = 10; +>this.a : Symbol(a, Decl(mod.js, 1, 20)) +>this : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0)) +>a : Symbol(a, Decl(mod.js, 1, 20)) + +this.a; // ok +>this.a : Symbol(a, Decl(mod.js, 1, 20)) +>this : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0)) +>a : Symbol(a, Decl(mod.js, 1, 20)) + +module.exports.a; // should be ok but doesn't have the right type +>module.exports : Symbol(exports, Decl(decl.d.ts, 0, 21)) +>module : Symbol(module, Decl(decl.d.ts, 0, 11)) +>exports : Symbol(exports, Decl(decl.d.ts, 0, 21)) + +a; // error: not actually at top-level in a module + diff --git a/tests/baselines/reference/topLevelThisAssignment2.types b/tests/baselines/reference/topLevelThisAssignment2.types new file mode 100644 index 0000000000000..37de14b5b654d --- /dev/null +++ b/tests/baselines/reference/topLevelThisAssignment2.types @@ -0,0 +1,52 @@ +=== tests/cases/conformance/salsa/use.js === +var mod = require('./mod') +>mod : typeof "tests/cases/conformance/salsa/mod" +>require('./mod') : typeof "tests/cases/conformance/salsa/mod" +>require : (name: string) => any +>'./mod' : "./mod" + +mod.a; +>mod.a : number +>mod : typeof "tests/cases/conformance/salsa/mod" +>a : number + +=== tests/cases/conformance/salsa/decl.d.ts === +declare var module: { exports: any }; +>module : { exports: any; } +>exports : any + +declare function require(name: string): any; +>require : (name: string) => any +>name : string + +=== tests/cases/conformance/salsa/mod.js === +/// +module.exports = {}; +>module.exports = {} : { [x: string]: any; } +>module.exports : any +>module : { exports: any; } +>exports : any +>{} : { [x: string]: any; } + +this.a = 10; +>this.a = 10 : 10 +>this.a : number +>this : typeof "tests/cases/conformance/salsa/mod" +>a : number +>10 : 10 + +this.a; // ok +>this.a : number +>this : typeof "tests/cases/conformance/salsa/mod" +>a : number + +module.exports.a; // should be ok but doesn't have the right type +>module.exports.a : any +>module.exports : any +>module : { exports: any; } +>exports : any +>a : any + +a; // error: not actually at top-level in a module +>a : any + diff --git a/tests/baselines/reference/typeFromPropertyAssignment9.symbols b/tests/baselines/reference/typeFromPropertyAssignment9.symbols index a4211cdefe70a..742bf83761b2c 100644 --- a/tests/baselines/reference/typeFromPropertyAssignment9.symbols +++ b/tests/baselines/reference/typeFromPropertyAssignment9.symbols @@ -117,6 +117,10 @@ min.nest = this.min.nest || function () { }; >min.nest : Symbol(nest, Decl(a.js, 29, 27)) >min : Symbol(min, Decl(a.js, 29, 3)) >nest : Symbol(nest, Decl(a.js, 29, 27)) +>this.min.nest : Symbol(nest, Decl(a.js, 29, 27)) +>this.min : Symbol(min, Decl(a.js, 29, 3)) +>min : Symbol(min, Decl(a.js, 29, 3)) +>nest : Symbol(nest, Decl(a.js, 29, 27)) min.nest.other = self.min.nest.other || class { }; >min.nest.other : Symbol((Anonymous function).other, Decl(a.js, 30, 44)) diff --git a/tests/baselines/reference/typeFromPropertyAssignment9.types b/tests/baselines/reference/typeFromPropertyAssignment9.types index bd1740fa6e118..b438c68479e2e 100644 --- a/tests/baselines/reference/typeFromPropertyAssignment9.types +++ b/tests/baselines/reference/typeFromPropertyAssignment9.types @@ -157,11 +157,11 @@ min.nest = this.min.nest || function () { }; >min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; } >nest : { (): void; other: typeof (Anonymous class); } >this.min.nest || function () { } : { (): void; other: typeof (Anonymous class); } ->this.min.nest : any ->this.min : any ->this : any ->min : any ->nest : any +>this.min.nest : { (): void; other: typeof (Anonymous class); } +>this.min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; } +>this : { [x: string]: any; eval(x: string): any; parseInt(s: string, radix?: number): number; parseFloat(string: string): number; isNaN(number: number): boolean; isFinite(number: number): boolean; decodeURI(encodedURI: string): string; decodeURIComponent(encodedURIComponent: string): string; encodeURI(uri: string): string; encodeURIComponent(uriComponent: string): string; escape(string: string): string; unescape(string: string): string; readonly NaN: number; readonly Infinity: number; readonly Object: ObjectConstructor; readonly Function: FunctionConstructor; readonly String: StringConstructor; readonly Boolean: BooleanConstructor; readonly Number: NumberConstructor; readonly Math: Math; readonly Date: DateConstructor; readonly RegExp: RegExpConstructor; readonly Error: ErrorConstructor; readonly EvalError: EvalErrorConstructor; readonly RangeError: RangeErrorConstructor; readonly ReferenceError: ReferenceErrorConstructor; readonly SyntaxError: SyntaxErrorConstructor; readonly TypeError: TypeErrorConstructor; readonly URIError: URIErrorConstructor; readonly JSON: JSON; readonly Array: ArrayConstructor; Promise: PromiseConstructor; readonly ArrayBuffer: ArrayBufferConstructor; readonly DataView: DataViewConstructor; readonly Int8Array: Int8ArrayConstructor; readonly Uint8Array: Uint8ArrayConstructor; readonly Uint8ClampedArray: Uint8ClampedArrayConstructor; readonly Int16Array: Int16ArrayConstructor; readonly Uint16Array: Uint16ArrayConstructor; readonly Int32Array: Int32ArrayConstructor; readonly Uint32Array: Uint32ArrayConstructor; readonly Float32Array: Float32ArrayConstructor; readonly Float64Array: Float64ArrayConstructor; Intl: typeof Intl; Symbol: SymbolConstructor; Map: MapConstructor; WeakMap: WeakMapConstructor; Set: SetConstructor; WeakSet: WeakSetConstructor; Reflect: typeof Reflect; Proxy: ProxyConstructor; my: { [x: string]: any; method: (n: number) => number; number: number; object: { [x: string]: any; }; predicate: { [x: string]: any; query: { (): void; another: () => number; result: string; }; sort: (first: number, second: number) => number; type: typeof (Anonymous class); }; }; q: any; min: { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; }; undefined: undefined; } +>min : { [x: string]: any; nest: { (): void; other: typeof (Anonymous class); }; property: { [x: string]: any; }; } +>nest : { (): void; other: typeof (Anonymous class); } >function () { } : { (): void; other: typeof (Anonymous class); } min.nest.other = self.min.nest.other || class { }; diff --git a/tests/cases/conformance/salsa/topLevelThisAssignment.ts b/tests/cases/conformance/salsa/topLevelThisAssignment.ts index 162bed0c30fc7..4d23b0c39a79a 100644 --- a/tests/cases/conformance/salsa/topLevelThisAssignment.ts +++ b/tests/cases/conformance/salsa/topLevelThisAssignment.ts @@ -1,10 +1,18 @@ // @out: output.js +// @checkJs: true // @allowJs: true // @Filename: a.js this.a = 10; this.a; a; +unknown; +this.unknown; + +// also, improved types for this-prefixed globals like eval: +this.eval('hi'); // @Filename: b.js this.a; a; +unknown; +this.unknown; diff --git a/tests/cases/conformance/salsa/topLevelThisAssignment2.ts b/tests/cases/conformance/salsa/topLevelThisAssignment2.ts new file mode 100644 index 0000000000000..a40534d5092b9 --- /dev/null +++ b/tests/cases/conformance/salsa/topLevelThisAssignment2.ts @@ -0,0 +1,17 @@ +// @noEmit: true +// @allowJs: true +// @checkJs: true +// @Filename: decl.d.ts +declare var module: { exports: any }; +declare function require(name: string): any; +// @Filename: mod.js +/// +module.exports = {}; +this.a = 10; +this.a; // ok +module.exports.a; // should be ok but doesn't have the right type +a; // error: not actually at top-level in a module + +// @Filename: use.js +var mod = require('./mod') +mod.a;