Explicitly typed prototype assignments are context sensitive (#25688)
* Explicitly typed prototype assignments:ctx sensitive Follow up to #25619: Add the necessary code to type `prototype` correctly in prototype assignments so that code like `F.prototype = { ... }` properly makes the object literal context sensitive. * Fix lint
This commit is contained in:
parent
60986adee5
commit
5b21cbc0c9
11 changed files with 53 additions and 52 deletions
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
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(70,7): error TS7006: Parameter 'n' implicitly has an 'any' type.
|
||||
|
||||
|
||||
==== tests/cases/conformance/salsa/test.js (2 errors) ====
|
||||
==== tests/cases/conformance/salsa/test.js (1 errors) ====
|
||||
/** @typedef {{
|
||||
status: 'done'
|
||||
m(n: number): void
|
||||
|
@ -76,13 +75,11 @@ tests/cases/conformance/salsa/test.js(70,7): error TS7006: Parameter 'n' implici
|
|||
F.prototype = {
|
||||
status: "done",
|
||||
m(n) { }
|
||||
~
|
||||
!!! error TS7006: Parameter 'n' implicitly has an 'any' type.
|
||||
}
|
||||
|
||||
==== tests/cases/conformance/salsa/mod.js (1 errors) ====
|
||||
// module.exports assignment
|
||||
/** @type {{ status: 'done' }} */
|
||||
/** @type {{ status: 'done', m(n: number): void }} */
|
||||
module.exports = {
|
||||
status: "done",
|
||||
m(n) { }
|
||||
|
|
|
@ -158,7 +158,7 @@ F.prototype = {
|
|||
|
||||
=== tests/cases/conformance/salsa/mod.js ===
|
||||
// module.exports assignment
|
||||
/** @type {{ status: 'done' }} */
|
||||
/** @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))
|
||||
|
|
|
@ -172,24 +172,24 @@ function F() {
|
|||
}
|
||||
/** @type {DoneStatus} */
|
||||
F.prototype = {
|
||||
>F.prototype = { status: "done", m(n) { }} : { status: string; m(n: any): void; }
|
||||
>F.prototype : { [x: string]: any; }
|
||||
>F.prototype = { status: "done", m(n) { }} : { status: "done"; m(n: number): void; }
|
||||
>F.prototype : { status: "done"; m(n: number): void; }
|
||||
>F : typeof F
|
||||
>prototype : { [x: string]: any; }
|
||||
>{ status: "done", m(n) { }} : { status: string; m(n: any): void; }
|
||||
>prototype : { status: "done"; m(n: number): void; }
|
||||
>{ status: "done", m(n) { }} : { status: "done"; m(n: number): void; }
|
||||
|
||||
status: "done",
|
||||
>status : string
|
||||
>status : "done"
|
||||
>"done" : "done"
|
||||
|
||||
m(n) { }
|
||||
>m : (n: any) => void
|
||||
>n : any
|
||||
>m : (n: number) => void
|
||||
>n : number
|
||||
}
|
||||
|
||||
=== tests/cases/conformance/salsa/mod.js ===
|
||||
// module.exports assignment
|
||||
/** @type {{ status: 'done' }} */
|
||||
/** @type {{ status: 'done', m(n: number): void }} */
|
||||
module.exports = {
|
||||
>module.exports = { status: "done", m(n) { }} : { status: string; m(n: any): void; }
|
||||
>module.exports : any
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -77,7 +77,7 @@ F.prototype = {
|
|||
|
||||
// @Filename: mod.js
|
||||
// module.exports assignment
|
||||
/** @type {{ status: 'done' }} */
|
||||
/** @type {{ status: 'done', m(n: number): void }} */
|
||||
module.exports = {
|
||||
status: "done",
|
||||
m(n) { }
|
||||
|
|
Loading…
Reference in a new issue