Revert the revert of explicitly typed special assignments (#25727)

* Revert "Revert "Explicitly typed special assignments are context sensitive (#25619)""

This reverts commit 16676f2707.

* Revert "Revert "Explicitly typed prototype assignments are context sensitive (#25688)""

This reverts commit ff8c30d636.
This commit is contained in:
Nathan Shively-Sanders
2018-07-17 10:02:51 -07:00
committed by GitHub
parent d9ed9177fe
commit 1edc975f15
13 changed files with 617 additions and 59 deletions

View File

@@ -4714,6 +4714,10 @@ namespace ts {
// function/class/{} assignments are fresh declarations, not property assignments, so only add prototype assignments
const specialDeclaration = getAssignedJavascriptInitializer(symbol.valueDeclaration);
if (specialDeclaration) {
const tag = getJSDocTypeTag(specialDeclaration);
if (tag && tag.typeExpression) {
return getTypeFromTypeNode(tag.typeExpression);
}
return getWidenedLiteralType(checkExpressionCached(specialDeclaration));
}
const types: Type[] = [];
@@ -5081,7 +5085,7 @@ namespace ts {
}
function getJSInitializerType(decl: Node, symbol: Symbol, init: Expression | undefined): Type | undefined {
if (init && isInJavaScriptFile(init) && isObjectLiteralExpression(init)) {
if (init && isInJavaScriptFile(init) && isObjectLiteralExpression(init) && init.properties.length === 0) {
const exports = createSymbolTable();
while (isBinaryExpression(decl) || isPropertyAccessExpression(decl)) {
const s = getSymbolOfNode(decl);
@@ -15786,22 +15790,22 @@ namespace ts {
}
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
// Don't do this for special property assignments to avoid circularity.
// Don't do this for special property assignments unless there is a type tag on the assignment, to avoid circularity from checking the right operand.
function isContextSensitiveAssignment(binaryExpression: BinaryExpression): boolean {
const kind = getSpecialPropertyAssignmentKind(binaryExpression);
switch (kind) {
case SpecialPropertyAssignmentKind.None:
return true;
case SpecialPropertyAssignmentKind.Property:
case SpecialPropertyAssignmentKind.ExportsProperty:
case SpecialPropertyAssignmentKind.Prototype:
case SpecialPropertyAssignmentKind.PrototypeProperty:
// If `binaryExpression.left` was assigned a symbol, then this is a new declaration; otherwise it is an assignment to an existing declaration.
// See `bindStaticPropertyAssignment` in `binder.ts`.
return !binaryExpression.left.symbol;
case SpecialPropertyAssignmentKind.ExportsProperty:
case SpecialPropertyAssignmentKind.ModuleExports:
case SpecialPropertyAssignmentKind.PrototypeProperty:
return !binaryExpression.left.symbol || binaryExpression.left.symbol.valueDeclaration && !!getJSDocTypeTag(binaryExpression.left.symbol.valueDeclaration);
case SpecialPropertyAssignmentKind.ThisProperty:
case SpecialPropertyAssignmentKind.Prototype:
return false;
case SpecialPropertyAssignmentKind.ModuleExports:
return !binaryExpression.symbol || binaryExpression.symbol.valueDeclaration && !!getJSDocTypeTag(binaryExpression.symbol.valueDeclaration);
default:
return Debug.assertNever(kind);
}

View File

@@ -86,9 +86,9 @@ A.prototype = B.prototype = {
>A : typeof A
>prototype : { [x: string]: any; m(n: number): number; }
>B.prototype = { /** @param {number} n */ m(n) { return n + 1 }} : { [x: string]: any; m(n: number): number; }
>B.prototype : { [x: string]: any; }
>B.prototype : { [x: string]: any; m(n: number): number; }
>B : typeof B
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(n: number): number; }
>{ /** @param {number} n */ m(n) { return n + 1 }} : { [x: string]: any; m(n: number): number; }
/** @param {number} n */

View File

@@ -7,11 +7,11 @@ export function abc(a, b, c) { return 5; }
>5 : 5
module.exports = { abc };
>module.exports = { abc } : { [x: string]: any; abc: (a: any, b: any, c: any) => number; }
>module.exports = { abc } : { abc: (a: any, b: any, c: any) => number; }
>module.exports : any
>module : any
>exports : any
>{ abc } : { [x: string]: any; abc: (a: any, b: any, c: any) => number; }
>{ abc } : { abc: (a: any, b: any, c: any) => number; }
>abc : (a: any, b: any, c: any) => number
=== tests/cases/conformance/salsa/use.js ===

View File

@@ -0,0 +1,89 @@
tests/cases/conformance/salsa/mod.js(5,7): error TS7006: Parameter 'n' implicitly has an 'any' type.
tests/cases/conformance/salsa/test.js(52,7): error TS7006: Parameter 'n' implicitly has an 'any' type.
==== tests/cases/conformance/salsa/test.js (1 errors) ====
/** @typedef {{
status: 'done'
m(n: number): void
}} DoneStatus */
// property assignment
var ns = {}
/** @type {DoneStatus} */
ns.x = {
status: 'done',
m(n) { }
}
ns.x = {
status: 'done',
m(n) { }
}
ns.x
// this-property assignment
class Thing {
constructor() {
/** @type {DoneStatus} */
this.s = {
status: 'done',
m(n) { }
}
}
fail() {
this.s = {
status: 'done',
m(n) { }
}
}
}
// exports-property assignment
/** @type {DoneStatus} */
exports.x = {
status: "done",
m(n) { }
}
exports.x
/** @type {DoneStatus} contextual typing is allowed, but module.exports.y: any.
Guess it doesn't check the type tag? */
module.exports.y = {
status: "done",
m(n) { }
~
!!! error TS7006: Parameter 'n' implicitly has an 'any' type.
}
module.exports.y
// prototype-property assignment
/** @type {DoneStatus} */
Thing.prototype.x = {
status: 'done',
m(n) { }
}
Thing.prototype.x
// prototype assignment
function F() {
}
/** @type {DoneStatus} */
F.prototype = {
status: "done",
m(n) { }
}
==== tests/cases/conformance/salsa/mod.js (1 errors) ====
// module.exports assignment
/** @type {{ status: 'done', m(n: number): void }} */
module.exports = {
status: "done",
m(n) { }
~
!!! error TS7006: Parameter 'n' implicitly has an 'any' type.
}

View File

@@ -0,0 +1,173 @@
=== tests/cases/conformance/salsa/test.js ===
/** @typedef {{
status: 'done'
m(n: number): void
}} DoneStatus */
// property assignment
var ns = {}
>ns : Symbol(ns, Decl(test.js, 6, 3))
/** @type {DoneStatus} */
ns.x = {
>ns.x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
>ns : Symbol(ns, Decl(test.js, 6, 3))
>x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
status: 'done',
>status : Symbol(status, Decl(test.js, 8, 8))
m(n) { }
>m : Symbol(m, Decl(test.js, 9, 19))
>n : Symbol(n, Decl(test.js, 10, 6))
}
ns.x = {
>ns.x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
>ns : Symbol(ns, Decl(test.js, 6, 3))
>x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
status: 'done',
>status : Symbol(status, Decl(test.js, 13, 8))
m(n) { }
>m : Symbol(m, Decl(test.js, 14, 19))
>n : Symbol(n, Decl(test.js, 15, 6))
}
ns.x
>ns.x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
>ns : Symbol(ns, Decl(test.js, 6, 3))
>x : Symbol(ns.x, Decl(test.js, 6, 11), Decl(test.js, 11, 1))
// this-property assignment
class Thing {
>Thing : Symbol(Thing, Decl(test.js, 17, 4))
constructor() {
/** @type {DoneStatus} */
this.s = {
>this.s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
>this : Symbol(Thing, Decl(test.js, 17, 4))
>s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
status: 'done',
>status : Symbol(status, Decl(test.js, 24, 18))
m(n) { }
>m : Symbol(m, Decl(test.js, 25, 27))
>n : Symbol(n, Decl(test.js, 26, 14))
}
}
fail() {
>fail : Symbol(Thing.fail, Decl(test.js, 28, 5))
this.s = {
>this.s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
>this : Symbol(Thing, Decl(test.js, 17, 4))
>s : Symbol(Thing.s, Decl(test.js, 22, 19), Decl(test.js, 30, 12))
status: 'done',
>status : Symbol(status, Decl(test.js, 31, 18))
m(n) { }
>m : Symbol(m, Decl(test.js, 32, 27))
>n : Symbol(n, Decl(test.js, 33, 14))
}
}
}
// exports-property assignment
/** @type {DoneStatus} */
exports.x = {
>exports.x : Symbol(x, Decl(test.js, 36, 1))
>exports : Symbol(x, Decl(test.js, 36, 1))
>x : Symbol(x, Decl(test.js, 36, 1))
status: "done",
>status : Symbol(status, Decl(test.js, 41, 13))
m(n) { }
>m : Symbol(m, Decl(test.js, 42, 19))
>n : Symbol(n, Decl(test.js, 43, 6))
}
exports.x
>exports.x : Symbol(x, Decl(test.js, 36, 1))
>exports : Symbol("tests/cases/conformance/salsa/test", Decl(test.js, 0, 0))
>x : Symbol(x, Decl(test.js, 36, 1))
/** @type {DoneStatus} contextual typing is allowed, but module.exports.y: any.
Guess it doesn't check the type tag? */
module.exports.y = {
>module.exports : Symbol(y, Decl(test.js, 45, 9))
>module : Symbol(module)
>y : Symbol(y, Decl(test.js, 45, 9))
status: "done",
>status : Symbol(status, Decl(test.js, 49, 20))
m(n) { }
>m : Symbol(m, Decl(test.js, 50, 19))
>n : Symbol(n, Decl(test.js, 51, 6))
}
module.exports.y
>module : Symbol(module)
// prototype-property assignment
/** @type {DoneStatus} */
Thing.prototype.x = {
>Thing.prototype.x : Symbol(Thing.x, Decl(test.js, 53, 16))
>Thing.prototype : Symbol(Thing.x, Decl(test.js, 53, 16))
>Thing : Symbol(Thing, Decl(test.js, 17, 4))
>prototype : Symbol(Thing.prototype)
>x : Symbol(Thing.x, Decl(test.js, 53, 16))
status: 'done',
>status : Symbol(status, Decl(test.js, 57, 21))
m(n) { }
>m : Symbol(m, Decl(test.js, 58, 19))
>n : Symbol(n, Decl(test.js, 59, 6))
}
Thing.prototype.x
>Thing.prototype.x : Symbol(Thing.x, Decl(test.js, 53, 16))
>Thing.prototype : Symbol(Thing.prototype)
>Thing : Symbol(Thing, Decl(test.js, 17, 4))
>prototype : Symbol(Thing.prototype)
>x : Symbol(Thing.x, Decl(test.js, 53, 16))
// prototype assignment
function F() {
>F : Symbol(F, Decl(test.js, 61, 17), Decl(test.js, 65, 1))
}
/** @type {DoneStatus} */
F.prototype = {
>F.prototype : Symbol(F.prototype, Decl(test.js, 65, 1))
>F : Symbol(F, Decl(test.js, 61, 17), Decl(test.js, 65, 1))
>prototype : Symbol(F.prototype, Decl(test.js, 65, 1))
status: "done",
>status : Symbol(status, Decl(test.js, 67, 15))
m(n) { }
>m : Symbol(m, Decl(test.js, 68, 19))
>n : Symbol(n, Decl(test.js, 69, 6))
}
=== tests/cases/conformance/salsa/mod.js ===
// module.exports assignment
/** @type {{ status: 'done', m(n: number): void }} */
module.exports = {
>module : Symbol(export=, Decl(mod.js, 0, 0))
>exports : Symbol(export=, Decl(mod.js, 0, 0))
status: "done",
>status : Symbol(status, Decl(mod.js, 2, 18))
m(n) { }
>m : Symbol(m, Decl(mod.js, 3, 19))
>n : Symbol(n, Decl(mod.js, 4, 6))
}

View File

@@ -0,0 +1,208 @@
=== tests/cases/conformance/salsa/test.js ===
/** @typedef {{
status: 'done'
m(n: number): void
}} DoneStatus */
// property assignment
var ns = {}
>ns : { [x: string]: any; x: { status: "done"; m(n: number): void; }; }
>{} : { [x: string]: any; }
/** @type {DoneStatus} */
ns.x = {
>ns.x = { status: 'done', m(n) { }} : { status: "done"; m(n: number): void; }
>ns.x : { status: "done"; m(n: number): void; }
>ns : { [x: string]: any; x: { status: "done"; m(n: number): void; }; }
>x : { status: "done"; m(n: number): void; }
>{ status: 'done', m(n) { }} : { status: "done"; m(n: number): void; }
status: 'done',
>status : "done"
>'done' : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
ns.x = {
>ns.x = { status: 'done', m(n) { }} : { status: "done"; m(n: number): void; }
>ns.x : { status: "done"; m(n: number): void; }
>ns : { [x: string]: any; x: { status: "done"; m(n: number): void; }; }
>x : { status: "done"; m(n: number): void; }
>{ status: 'done', m(n) { }} : { status: "done"; m(n: number): void; }
status: 'done',
>status : "done"
>'done' : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
ns.x
>ns.x : { status: "done"; m(n: number): void; }
>ns : { [x: string]: any; x: { status: "done"; m(n: number): void; }; }
>x : { status: "done"; m(n: number): void; }
// this-property assignment
class Thing {
>Thing : Thing
constructor() {
/** @type {DoneStatus} */
this.s = {
>this.s = { status: 'done', m(n) { } } : { status: "done"; m(n: number): void; }
>this.s : { status: "done"; m(n: number): void; }
>this : this
>s : { status: "done"; m(n: number): void; }
>{ status: 'done', m(n) { } } : { status: "done"; m(n: number): void; }
status: 'done',
>status : "done"
>'done' : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
}
fail() {
>fail : () => void
this.s = {
>this.s = { status: 'done', m(n) { } } : { status: "done"; m(n: number): void; }
>this.s : { status: "done"; m(n: number): void; }
>this : this
>s : { status: "done"; m(n: number): void; }
>{ status: 'done', m(n) { } } : { status: "done"; m(n: number): void; }
status: 'done',
>status : "done"
>'done' : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
}
}
// exports-property assignment
/** @type {DoneStatus} */
exports.x = {
>exports.x = { status: "done", m(n) { }} : { status: "done"; m(n: number): void; }
>exports.x : { status: "done"; m(n: number): void; }
>exports : typeof import("tests/cases/conformance/salsa/test")
>x : { status: "done"; m(n: number): void; }
>{ status: "done", m(n) { }} : { status: "done"; m(n: number): void; }
status: "done",
>status : "done"
>"done" : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
exports.x
>exports.x : { status: "done"; m(n: number): void; }
>exports : typeof import("tests/cases/conformance/salsa/test")
>x : { status: "done"; m(n: number): void; }
/** @type {DoneStatus} contextual typing is allowed, but module.exports.y: any.
Guess it doesn't check the type tag? */
module.exports.y = {
>module.exports.y = { status: "done", m(n) { }} : { status: string; m(n: any): void; }
>module.exports.y : any
>module.exports : any
>module : any
>exports : any
>y : any
>{ status: "done", m(n) { }} : { status: string; m(n: any): void; }
status: "done",
>status : string
>"done" : "done"
m(n) { }
>m : (n: any) => void
>n : any
}
module.exports.y
>module.exports.y : any
>module.exports : any
>module : any
>exports : any
>y : any
// prototype-property assignment
/** @type {DoneStatus} */
Thing.prototype.x = {
>Thing.prototype.x = { status: 'done', m(n) { }} : { status: "done"; m(n: number): void; }
>Thing.prototype.x : { status: "done"; m(n: number): void; }
>Thing.prototype : Thing
>Thing : typeof Thing
>prototype : Thing
>x : { status: "done"; m(n: number): void; }
>{ status: 'done', m(n) { }} : { status: "done"; m(n: number): void; }
status: 'done',
>status : "done"
>'done' : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
Thing.prototype.x
>Thing.prototype.x : { status: "done"; m(n: number): void; }
>Thing.prototype : Thing
>Thing : typeof Thing
>prototype : Thing
>x : { status: "done"; m(n: number): void; }
// prototype assignment
function F() {
>F : typeof F
}
/** @type {DoneStatus} */
F.prototype = {
>F.prototype = { status: "done", m(n) { }} : { status: "done"; m(n: number): void; }
>F.prototype : { status: "done"; m(n: number): void; }
>F : typeof F
>prototype : { status: "done"; m(n: number): void; }
>{ status: "done", m(n) { }} : { status: "done"; m(n: number): void; }
status: "done",
>status : "done"
>"done" : "done"
m(n) { }
>m : (n: number) => void
>n : number
}
=== tests/cases/conformance/salsa/mod.js ===
// module.exports assignment
/** @type {{ status: 'done', m(n: number): void }} */
module.exports = {
>module.exports = { status: "done", m(n) { }} : { status: string; m(n: any): void; }
>module.exports : any
>module : any
>exports : any
>{ status: "done", m(n) { }} : { status: string; m(n: any): void; }
status: "done",
>status : string
>"done" : "done"
m(n) { }
>m : (n: any) => void
>n : any
}

View File

@@ -223,19 +223,19 @@ multipleDeclarationAlias5.func9 = function () { };
>function () { } : () => void
var multipleDeclarationAlias6 = exports = module.exports = {};
>multipleDeclarationAlias6 : { [x: string]: any; }
>exports = module.exports = {} : { [x: string]: any; }
>multipleDeclarationAlias6 : {}
>exports = module.exports = {} : {}
>exports : typeof import("tests/cases/conformance/salsa/b")
>module.exports = {} : { [x: string]: any; }
>module.exports = {} : {}
>module.exports : any
>module : any
>exports : any
>{} : { [x: string]: any; }
>{} : {}
multipleDeclarationAlias6.func10 = function () { };
>multipleDeclarationAlias6.func10 = function () { } : () => void
>multipleDeclarationAlias6.func10 : any
>multipleDeclarationAlias6 : { [x: string]: any; }
>multipleDeclarationAlias6 : {}
>func10 : any
>function () { } : () => void
@@ -294,13 +294,13 @@ module.exports.func12 = function () { };
>function () { } : () => void
exports = module.exports = {};
>exports = module.exports = {} : { [x: string]: any; }
>exports = module.exports = {} : {}
>exports : typeof import("tests/cases/conformance/salsa/b")
>module.exports = {} : { [x: string]: any; }
>module.exports = {} : {}
>module.exports : any
>module : any
>exports : any
>{} : { [x: string]: any; }
>{} : {}
exports.func13 = function () { };
>exports.func13 = function () { } : () => void
@@ -319,13 +319,13 @@ module.exports.func14 = function () { };
>function () { } : () => void
exports = module.exports = {};
>exports = module.exports = {} : { [x: string]: any; }
>exports = module.exports = {} : {}
>exports : typeof import("tests/cases/conformance/salsa/b")
>module.exports = {} : { [x: string]: any; }
>module.exports = {} : {}
>module.exports : any
>module : any
>exports : any
>{} : { [x: string]: any; }
>{} : {}
exports.func15 = function () { };
>exports.func15 = function () { } : () => void
@@ -369,11 +369,11 @@ module.exports.func18 = function () { };
>function () { } : () => void
module.exports = {};
>module.exports = {} : { [x: string]: any; }
>module.exports = {} : {}
>module.exports : any
>module : any
>exports : any
>{} : { [x: string]: any; }
>{} : {}
exports.func19 = function () { };
>exports.func19 = function () { } : () => void

View File

@@ -5,9 +5,9 @@ var Inner = function() {}
Inner.prototype = {
>Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Inner.prototype : { [x: string]: any; }
>Inner.prototype : { [x: string]: any; m(): void; i: number; }
>Inner : typeof Inner
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(): void; i: number; }
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
@@ -21,18 +21,18 @@ Inner.prototype = {
Inner.prototype.j = 2
>Inner.prototype.j = 2 : 2
>Inner.prototype.j : any
>Inner.prototype : { [x: string]: any; }
>Inner.prototype : { [x: string]: any; m(): void; i: number; }
>Inner : typeof Inner
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(): void; i: number; }
>j : any
>2 : 2
/** @type {string} */
Inner.prototype.k;
>Inner.prototype.k : any
>Inner.prototype : { [x: string]: any; }
>Inner.prototype : { [x: string]: any; m(): void; i: number; }
>Inner : typeof Inner
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(): void; i: number; }
>k : any
var inner = new Inner()

View File

@@ -12,11 +12,11 @@ Outer.Inner = function() {}
Outer.Inner.prototype = {
>Outer.Inner.prototype = { m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
>Outer.Inner.prototype : { [x: string]: any; }
>Outer.Inner.prototype : { [x: string]: any; m(): void; i: number; }
>Outer.Inner : typeof Inner
>Outer : typeof Outer
>Inner : typeof Inner
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(): void; i: number; }
>{ m() { }, i: 1} : { [x: string]: any; m(): void; i: number; }
m() { },
@@ -30,22 +30,22 @@ Outer.Inner.prototype = {
Outer.Inner.prototype.j = 2
>Outer.Inner.prototype.j = 2 : 2
>Outer.Inner.prototype.j : any
>Outer.Inner.prototype : { [x: string]: any; }
>Outer.Inner.prototype : { [x: string]: any; m(): void; i: number; }
>Outer.Inner : typeof Inner
>Outer : typeof Outer
>Inner : typeof Inner
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(): void; i: number; }
>j : any
>2 : 2
/** @type {string} */
Outer.Inner.prototype.k;
>Outer.Inner.prototype.k : any
>Outer.Inner.prototype : { [x: string]: any; }
>Outer.Inner.prototype : { [x: string]: any; m(): void; i: number; }
>Outer.Inner : typeof Inner
>Outer : typeof Outer
>Inner : typeof Inner
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; m(): void; i: number; }
>k : any
var inner = new Outer.Inner()

View File

@@ -5,19 +5,19 @@ var Outer = {};
=== tests/cases/conformance/salsa/work.js ===
Outer.Inner = function () {}
>Outer.Inner = function () {} : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner = function () {} : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer : typeof Outer
>Inner : { (): void; prototype: { [x: string]: any; }; }
>function () {} : { (): void; prototype: { [x: string]: any; }; }
>Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>function () {} : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : { [x: string]: any; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner.prototype : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer : typeof Outer
>Inner : { (): void; prototype: { [x: string]: any; }; }
>prototype : { [x: string]: any; }
>Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>prototype : { [x: string]: any; x: number; m(): void; }
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
@@ -47,9 +47,9 @@ inner.m()
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer : typeof Outer
>Inner : { (): void; prototype: { [x: string]: any; }; }
>Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
inno.x
>inno.x : number

View File

@@ -4,19 +4,19 @@ var Outer = {};
>{} : { [x: string]: any; }
Outer.Inner = function () {}
>Outer.Inner = function () {} : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner = function () {} : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer : typeof Outer
>Inner : { (): void; prototype: { [x: string]: any; }; }
>function () {} : { (): void; prototype: { [x: string]: any; }; }
>Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>function () {} : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
Outer.Inner.prototype = {
>Outer.Inner.prototype = { x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
>Outer.Inner.prototype : { [x: string]: any; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner.prototype : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer : typeof Outer
>Inner : { (): void; prototype: { [x: string]: any; }; }
>prototype : { [x: string]: any; }
>Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>prototype : { [x: string]: any; x: number; m(): void; }
>{ x: 1, m() { }} : { [x: string]: any; x: number; m(): void; }
x: 1,
@@ -45,9 +45,9 @@ inner.m()
var inno = new Outer.Inner()
>inno : { [x: string]: any; x: number; m(): void; }
>new Outer.Inner() : { [x: string]: any; x: number; m(): void; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; }; }
>Outer.Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
>Outer : typeof Outer
>Inner : { (): void; prototype: { [x: string]: any; }; }
>Inner : { (): void; prototype: { [x: string]: any; x: number; m(): void; }; }
inno.x
>inno.x : number

View File

@@ -10,9 +10,9 @@ function C() { this.p = 1; }
C.prototype = { q: 2 };
>C.prototype = { q: 2 } : { [x: string]: any; q: number; }
>C.prototype : { [x: string]: any; }
>C.prototype : { [x: string]: any; q: number; }
>C : typeof C
>prototype : { [x: string]: any; }
>prototype : { [x: string]: any; q: number; }
>{ q: 2 } : { [x: string]: any; q: number; }
>q : number
>2 : 2

View File

@@ -0,0 +1,84 @@
// @checkJs: true
// @allowJs: true
// @noEmit: true
// @Filename: test.js
// @strict: true
/** @typedef {{
status: 'done'
m(n: number): void
}} DoneStatus */
// property assignment
var ns = {}
/** @type {DoneStatus} */
ns.x = {
status: 'done',
m(n) { }
}
ns.x = {
status: 'done',
m(n) { }
}
ns.x
// this-property assignment
class Thing {
constructor() {
/** @type {DoneStatus} */
this.s = {
status: 'done',
m(n) { }
}
}
fail() {
this.s = {
status: 'done',
m(n) { }
}
}
}
// exports-property assignment
/** @type {DoneStatus} */
exports.x = {
status: "done",
m(n) { }
}
exports.x
/** @type {DoneStatus} contextual typing is allowed, but module.exports.y: any.
Guess it doesn't check the type tag? */
module.exports.y = {
status: "done",
m(n) { }
}
module.exports.y
// prototype-property assignment
/** @type {DoneStatus} */
Thing.prototype.x = {
status: 'done',
m(n) { }
}
Thing.prototype.x
// prototype assignment
function F() {
}
/** @type {DoneStatus} */
F.prototype = {
status: "done",
m(n) { }
}
// @Filename: mod.js
// module.exports assignment
/** @type {{ status: 'done', m(n: number): void }} */
module.exports = {
status: "done",
m(n) { }
}