fix(51521): Using a of property declared after an initializing constructor triggers an assertion failure in JS (#51524)

Fixes https://github.com/microsoft/TypeScript/issues/51521
This commit is contained in:
Oleksandr T
2023-01-21 00:43:23 +02:00
committed by GitHub
parent f576398194
commit 1d81c1dfef
7 changed files with 149 additions and 1 deletions

View File

@@ -3531,7 +3531,7 @@ export function isSpecialPropertyDeclaration(expr: PropertyAccessExpression | El
export function setValueDeclaration(symbol: Symbol, node: Declaration): void {
const { valueDeclaration } = symbol;
if (!valueDeclaration ||
!(node.flags & NodeFlags.Ambient && !(valueDeclaration.flags & NodeFlags.Ambient)) &&
!(node.flags & NodeFlags.Ambient && !isInJSFile(node) && !(valueDeclaration.flags & NodeFlags.Ambient)) &&
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
// other kinds of value declarations take precedence over modules and assignment declarations

View File

@@ -0,0 +1,27 @@
/test.js(3,9): error TS2322: Type '{}' is not assignable to type 'string'.
/test.js(6,5): error TS8009: The 'declare' modifier can only be used in TypeScript files.
/test.js(6,19): error TS8010: Type annotations can only be used in TypeScript files.
/test.js(9,19): error TS2339: Property 'foo' does not exist on type 'string'.
==== /test.js (4 errors) ====
class Foo {
constructor() {
this.prop = {};
~~~~~~~~~
!!! error TS2322: Type '{}' is not assignable to type 'string'.
}
declare prop: string;
~~~~~~~
!!! error TS8009: The 'declare' modifier can only be used in TypeScript files.
~~~~~~
!!! error TS8010: Type annotations can only be used in TypeScript files.
method() {
this.prop.foo
~~~
!!! error TS2339: Property 'foo' does not exist on type 'string'.
}
}

View File

@@ -0,0 +1,24 @@
=== /test.js ===
class Foo {
>Foo : Symbol(Foo, Decl(test.js, 0, 0))
constructor() {
this.prop = {};
>this.prop : Symbol(Foo.prop, Decl(test.js, 1, 19), Decl(test.js, 3, 5))
>this : Symbol(Foo, Decl(test.js, 0, 0))
>prop : Symbol(Foo.prop, Decl(test.js, 1, 19), Decl(test.js, 3, 5))
}
declare prop: string;
>prop : Symbol(Foo.prop, Decl(test.js, 1, 19), Decl(test.js, 3, 5))
method() {
>method : Symbol(Foo.method, Decl(test.js, 5, 25))
this.prop.foo
>this.prop : Symbol(Foo.prop, Decl(test.js, 1, 19), Decl(test.js, 3, 5))
>this : Symbol(Foo, Decl(test.js, 0, 0))
>prop : Symbol(Foo.prop, Decl(test.js, 1, 19), Decl(test.js, 3, 5))
}
}

View File

@@ -0,0 +1,28 @@
=== /test.js ===
class Foo {
>Foo : Foo
constructor() {
this.prop = {};
>this.prop = {} : {}
>this.prop : string
>this : this
>prop : string
>{} : {}
}
declare prop: string;
>prop : string
method() {
>method : () => void
this.prop.foo
>this.prop.foo : any
>this.prop : string
>this : this
>prop : string
>foo : any
}
}

View File

@@ -0,0 +1,38 @@
=== /a.js ===
// class C {
// constructor() {
// this.prop = "";
// }
// declare prop: string;
// method() {
// this.prop.foo
// ^^^
// | ----------------------------------------------------------------------
// | any
// | ----------------------------------------------------------------------
// }
// }
[
{
"marker": {
"fileName": "/a.js",
"position": 122,
"name": ""
},
"item": {
"kind": "",
"kindModifiers": "",
"textSpan": {
"start": 119,
"length": 3
},
"displayParts": [
{
"text": "any",
"kind": "keyword"
}
]
}
}
]

View File

@@ -0,0 +1,16 @@
// @allowJs: true
// @checkJs: true
// @noEmit: true
// @filename: /test.js
class Foo {
constructor() {
this.prop = {};
}
declare prop: string;
method() {
this.prop.foo
}
}

View File

@@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowJs: true
// @filename: /a.js
////class C {
//// constructor() {
//// this.prop = "";
//// }
//// declare prop: string;
//// method() {
//// this.prop.foo/**/
//// }
////}
verify.baselineQuickInfo();