Support prototype assignment with a function declaration (#25300)

Previously variable declaration+function expression worked.
Note that class expression/class declaration do not work, due to the way
they are specified. I added a test for future reference.
This commit is contained in:
Nathan Shively-Sanders
2018-07-05 09:04:28 -07:00
committed by GitHub
parent 1579bfdd46
commit 50ef631b59
8 changed files with 179 additions and 1 deletions

View File

@@ -19458,7 +19458,8 @@ namespace ts {
function getAssignedClassType(symbol: Symbol) {
const decl = symbol.valueDeclaration;
const assignmentSymbol = decl && decl.parent &&
(isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
(isFunctionDeclaration(decl) && getSymbolOfNode(decl) ||
isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
if (assignmentSymbol) {
const prototype = forEach(assignmentSymbol.declarations, getAssignedJavascriptPrototype);

View File

@@ -0,0 +1,26 @@
=== tests/cases/conformance/salsa/a.js ===
// mixed prototype-assignment+function declaration
function C() { this.p = 1; }
>C : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 28))
>p : Symbol(C.p, Decl(a.js, 1, 14))
C.prototype = { q: 2 };
>C.prototype : Symbol(C.prototype, Decl(a.js, 1, 28))
>C : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 28))
>prototype : Symbol(C.prototype, Decl(a.js, 1, 28))
>q : Symbol(q, Decl(a.js, 2, 15))
const c = new C()
>c : Symbol(c, Decl(a.js, 4, 5))
>C : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 28))
c.p
>c.p : Symbol(C.p, Decl(a.js, 1, 14))
>c : Symbol(c, Decl(a.js, 4, 5))
>p : Symbol(C.p, Decl(a.js, 1, 14))
c.q
>c.q : Symbol(q, Decl(a.js, 2, 15))
>c : Symbol(c, Decl(a.js, 4, 5))
>q : Symbol(q, Decl(a.js, 2, 15))

View File

@@ -0,0 +1,34 @@
=== tests/cases/conformance/salsa/a.js ===
// mixed prototype-assignment+function declaration
function C() { this.p = 1; }
>C : typeof C
>this.p = 1 : 1
>this.p : any
>this : any
>p : any
>1 : 1
C.prototype = { q: 2 };
>C.prototype = { q: 2 } : { [x: string]: any; q: number; }
>C.prototype : { [x: string]: any; }
>C : typeof C
>prototype : { [x: string]: any; }
>{ q: 2 } : { [x: string]: any; q: number; }
>q : number
>2 : 2
const c = new C()
>c : C & { [x: string]: any; q: number; }
>new C() : C & { [x: string]: any; q: number; }
>C : typeof C
c.p
>c.p : number
>c : C & { [x: string]: any; q: number; }
>p : number
c.q
>c.q : number
>c : C & { [x: string]: any; q: number; }
>q : number

View File

@@ -0,0 +1,23 @@
tests/cases/conformance/salsa/a.js(7,17): error TS2322: Type '{ [x: string]: any; q: number; }' is not assignable to type 'C'.
Object literal may only specify known properties, and 'q' does not exist in type 'C'.
tests/cases/conformance/salsa/a.js(11,3): error TS2339: Property 'q' does not exist on type 'C'.
==== tests/cases/conformance/salsa/a.js (2 errors) ====
// mixed prototype-assignment+class declaration
class C { constructor() { this.p = 1; } }
// Property assignment does nothing.
// You have to use Object.defineProperty(C, "prototype", { q: 2 })
// and that only works on classes with no superclass.
// (Object.defineProperty isn't recognised as a JS special assignment right now.)
C.prototype = { q: 2 };
~~~~
!!! error TS2322: Type '{ [x: string]: any; q: number; }' is not assignable to type 'C'.
!!! error TS2322: Object literal may only specify known properties, and 'q' does not exist in type 'C'.
const c = new C()
c.p
c.q
~
!!! error TS2339: Property 'q' does not exist on type 'C'.

View File

@@ -0,0 +1,30 @@
=== tests/cases/conformance/salsa/a.js ===
// mixed prototype-assignment+class declaration
class C { constructor() { this.p = 1; } }
>C : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 41))
>this.p : Symbol(C.p, Decl(a.js, 1, 25))
>this : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 41))
>p : Symbol(C.p, Decl(a.js, 1, 25))
// Property assignment does nothing.
// You have to use Object.defineProperty(C, "prototype", { q: 2 })
// and that only works on classes with no superclass.
// (Object.defineProperty isn't recognised as a JS special assignment right now.)
C.prototype = { q: 2 };
>C.prototype : Symbol(C.prototype, Decl(a.js, 1, 41))
>C : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 41))
>prototype : Symbol(C.prototype, Decl(a.js, 1, 41))
>q : Symbol(q, Decl(a.js, 6, 15))
const c = new C()
>c : Symbol(c, Decl(a.js, 8, 5))
>C : Symbol(C, Decl(a.js, 0, 0), Decl(a.js, 1, 41))
c.p
>c.p : Symbol(C.p, Decl(a.js, 1, 25))
>c : Symbol(c, Decl(a.js, 8, 5))
>p : Symbol(C.p, Decl(a.js, 1, 25))
c.q
>c : Symbol(c, Decl(a.js, 8, 5))

View File

@@ -0,0 +1,38 @@
=== tests/cases/conformance/salsa/a.js ===
// mixed prototype-assignment+class declaration
class C { constructor() { this.p = 1; } }
>C : C
>this.p = 1 : 1
>this.p : number
>this : this
>p : number
>1 : 1
// Property assignment does nothing.
// You have to use Object.defineProperty(C, "prototype", { q: 2 })
// and that only works on classes with no superclass.
// (Object.defineProperty isn't recognised as a JS special assignment right now.)
C.prototype = { q: 2 };
>C.prototype = { q: 2 } : { [x: string]: any; q: number; }
>C.prototype : C
>C : typeof C
>prototype : C
>{ q: 2 } : { [x: string]: any; q: number; }
>q : number
>2 : 2
const c = new C()
>c : C
>new C() : C
>C : typeof C
c.p
>c.p : number
>c : C
>p : number
c.q
>c.q : any
>c : C
>q : any

View File

@@ -0,0 +1,11 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: a.js
// mixed prototype-assignment+function declaration
function C() { this.p = 1; }
C.prototype = { q: 2 };
const c = new C()
c.p
c.q

View File

@@ -0,0 +1,15 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: a.js
// mixed prototype-assignment+class declaration
class C { constructor() { this.p = 1; } }
// Property assignment does nothing.
// You have to use Object.defineProperty(C, "prototype", { q: 2 })
// and that only works on classes with no superclass.
// (Object.defineProperty isn't recognised as a JS special assignment right now.)
C.prototype = { q: 2 };
const c = new C()
c.p
c.q