Stop reassigning .valueDeclaration to avoid replacing earlier declarations with late ones (#60857)

This commit is contained in:
Mateusz Burzyński
2025-05-15 18:51:34 +02:00
committed by GitHub
parent 0fb5e3a8cf
commit b86ab7dbe0
17 changed files with 486 additions and 13 deletions

View File

@@ -13657,9 +13657,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
symbol.declarations.push(member);
}
if (symbolFlags & SymbolFlags.Value) {
if (!symbol.valueDeclaration || symbol.valueDeclaration.kind !== member.kind) {
symbol.valueDeclaration = member;
}
setValueDeclaration(symbol, member);
}
}

View File

@@ -0,0 +1,61 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts] ////
//// [index.js]
// https://github.com/microsoft/TypeScript/issues/60590
export const kBar = Symbol("bar");
export class foo0 {
/**
* @protected
* @type {null | string}
*/
[kBar] = null;
get bar() {
return this[kBar];
}
/**
* @type {string}
*/
set bar(value) {
this[kBar] = value;
}
}
//// [index.js]
// https://github.com/microsoft/TypeScript/issues/60590
export const kBar = Symbol("bar");
export class foo0 {
/**
* @protected
* @type {null | string}
*/
[kBar] = null;
get bar() {
return this[kBar];
}
/**
* @type {string}
*/
set bar(value) {
this[kBar] = value;
}
}
//// [index.d.ts]
export const kBar: unique symbol;
export class foo0 {
/**
* @type {string}
*/
set bar(value: string | null);
get bar(): string | null;
/**
* @protected
* @type {null | string}
*/
protected [kBar]: null | string;
}

View File

@@ -0,0 +1,41 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts] ////
=== index.js ===
// https://github.com/microsoft/TypeScript/issues/60590
export const kBar = Symbol("bar");
>kBar : Symbol(kBar, Decl(index.js, 2, 12))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))
export class foo0 {
>foo0 : Symbol(foo0, Decl(index.js, 2, 34))
/**
* @protected
* @type {null | string}
*/
[kBar] = null;
>[kBar] : Symbol(foo0[kBar], Decl(index.js, 4, 19))
>kBar : Symbol(kBar, Decl(index.js, 2, 12))
get bar() {
>bar : Symbol(foo0.bar, Decl(index.js, 9, 18), Decl(index.js, 13, 5))
return this[kBar];
>this : Symbol(foo0, Decl(index.js, 2, 34))
>kBar : Symbol(kBar, Decl(index.js, 2, 12))
}
/**
* @type {string}
*/
set bar(value) {
>bar : Symbol(foo0.bar, Decl(index.js, 9, 18), Decl(index.js, 13, 5))
>value : Symbol(value, Decl(index.js, 17, 12))
this[kBar] = value;
>this : Symbol(foo0, Decl(index.js, 2, 34))
>kBar : Symbol(kBar, Decl(index.js, 2, 12))
>value : Symbol(value, Decl(index.js, 17, 12))
}
}

View File

@@ -0,0 +1,64 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS1.ts] ////
=== index.js ===
// https://github.com/microsoft/TypeScript/issues/60590
export const kBar = Symbol("bar");
>kBar : unique symbol
> : ^^^^^^^^^^^^^
>Symbol("bar") : unique symbol
> : ^^^^^^^^^^^^^
>Symbol : SymbolConstructor
> : ^^^^^^^^^^^^^^^^^
>"bar" : "bar"
> : ^^^^^
export class foo0 {
>foo0 : foo0
> : ^^^^
/**
* @protected
* @type {null | string}
*/
[kBar] = null;
>[kBar] : string | null
> : ^^^^^^^^^^^^^
>kBar : unique symbol
> : ^^^^^^^^^^^^^
get bar() {
>bar : string | null
> : ^^^^^^^^^^^^^
return this[kBar];
>this[kBar] : string | null
> : ^^^^^^^^^^^^^
>this : this
> : ^^^^
>kBar : unique symbol
> : ^^^^^^^^^^^^^
}
/**
* @type {string}
*/
set bar(value) {
>bar : string | null
> : ^^^^^^^^^^^^^
>value : string | null
> : ^^^^^^^^^^^^^
this[kBar] = value;
>this[kBar] = value : string | null
> : ^^^^^^^^^^^^^
>this[kBar] : string | null
> : ^^^^^^^^^^^^^
>this : this
> : ^^^^
>kBar : unique symbol
> : ^^^^^^^^^^^^^
>value : string | null
> : ^^^^^^^^^^^^^
}
}

View File

@@ -0,0 +1,40 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts] ////
//// [index.js]
const prop = 'prop';
export class foo1 {
constructor() {
this[prop] = 'bar'
}
/**
* @protected
* @type {string}
*/
[prop] = 'baz';
}
//// [index.js]
const prop = 'prop';
export class foo1 {
constructor() {
this[prop] = 'bar';
}
/**
* @protected
* @type {string}
*/
[prop] = 'baz';
}
//// [index.d.ts]
export class foo1 {
/**
* @protected
* @type {string}
*/
protected prop: string;
}

View File

@@ -0,0 +1,24 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts] ////
=== index.js ===
const prop = 'prop';
>prop : Symbol(prop, Decl(index.js, 0, 5))
export class foo1 {
>foo1 : Symbol(foo1, Decl(index.js, 0, 20))
constructor() {
this[prop] = 'bar'
>this : Symbol(foo1, Decl(index.js, 0, 20))
>prop : Symbol(prop, Decl(index.js, 0, 5))
}
/**
* @protected
* @type {string}
*/
[prop] = 'baz';
>[prop] : Symbol(foo1[prop], Decl(index.js, 5, 5))
>prop : Symbol(prop, Decl(index.js, 0, 5))
}

View File

@@ -0,0 +1,40 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS2.ts] ////
=== index.js ===
const prop = 'prop';
>prop : "prop"
> : ^^^^^^
>'prop' : "prop"
> : ^^^^^^
export class foo1 {
>foo1 : foo1
> : ^^^^
constructor() {
this[prop] = 'bar'
>this[prop] = 'bar' : "bar"
> : ^^^^^
>this[prop] : string
> : ^^^^^^
>this : this
> : ^^^^
>prop : "prop"
> : ^^^^^^
>'bar' : "bar"
> : ^^^^^
}
/**
* @protected
* @type {string}
*/
[prop] = 'baz';
>[prop] : string
> : ^^^^^^
>prop : "prop"
> : ^^^^^^
>'baz' : "baz"
> : ^^^^^
}

View File

@@ -0,0 +1,20 @@
index.js(5,9): error TS2322: Type 'number' is not assignable to type 'string'.
==== index.js (1 errors) ====
const prop = 'prop';
export class foo2 {
constructor() {
this[prop] = 12;
~~~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
}
/**
* @protected
* @type {string}
*/
prop = 'baz';
}

View File

@@ -0,0 +1,40 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts] ////
//// [index.js]
const prop = 'prop';
export class foo2 {
constructor() {
this[prop] = 12;
}
/**
* @protected
* @type {string}
*/
prop = 'baz';
}
//// [index.js]
const prop = 'prop';
export class foo2 {
constructor() {
this[prop] = 12;
}
/**
* @protected
* @type {string}
*/
prop = 'baz';
}
//// [index.d.ts]
export class foo2 {
/**
* @protected
* @type {string}
*/
protected prop: string;
}

View File

@@ -0,0 +1,23 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts] ////
=== index.js ===
const prop = 'prop';
>prop : Symbol(prop, Decl(index.js, 0, 5))
export class foo2 {
>foo2 : Symbol(foo2, Decl(index.js, 0, 20))
constructor() {
this[prop] = 12;
>this : Symbol(foo2, Decl(index.js, 0, 20))
>prop : Symbol(prop, Decl(index.js, 0, 5))
}
/**
* @protected
* @type {string}
*/
prop = 'baz';
>prop : Symbol(foo2.prop, Decl(index.js, 5, 5), Decl(index.js, 3, 19))
}

View File

@@ -0,0 +1,38 @@
//// [tests/cases/compiler/lateBoundAssignmentCandidateJS3.ts] ////
=== index.js ===
const prop = 'prop';
>prop : "prop"
> : ^^^^^^
>'prop' : "prop"
> : ^^^^^^
export class foo2 {
>foo2 : foo2
> : ^^^^
constructor() {
this[prop] = 12;
>this[prop] = 12 : 12
> : ^^
>this[prop] : string
> : ^^^^^^
>this : this
> : ^^^^
>prop : "prop"
> : ^^^^^^
>12 : 12
> : ^^
}
/**
* @protected
* @type {string}
*/
prop = 'baz';
>prop : string
> : ^^^^^^
>'baz' : "baz"
> : ^^^^^
}

View File

@@ -14,7 +14,7 @@ export class MyClass {
//// [lateBoundMethodNameAssigmentJS.d.ts]
export class MyClass {
[_symbol]: any;
[_symbol]: () => Promise<void>;
}
declare const _symbol: unique symbol;
export {};

View File

@@ -12,8 +12,10 @@ export class MyClass {
this[_symbol] = this[_symbol].bind(this);
>this : Symbol(MyClass, Decl(lateBoundMethodNameAssigmentJS.js, 0, 31))
>_symbol : Symbol(_symbol, Decl(lateBoundMethodNameAssigmentJS.js, 0, 5))
>this[_symbol].bind : Symbol(CallableFunction.bind, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>this : Symbol(MyClass, Decl(lateBoundMethodNameAssigmentJS.js, 0, 31))
>_symbol : Symbol(_symbol, Decl(lateBoundMethodNameAssigmentJS.js, 0, 5))
>bind : Symbol(CallableFunction.bind, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>this : Symbol(MyClass, Decl(lateBoundMethodNameAssigmentJS.js, 0, 31))
}

View File

@@ -17,28 +17,33 @@ export class MyClass {
constructor() {
this[_symbol] = this[_symbol].bind(this);
>this[_symbol] = this[_symbol].bind(this) : error
>this[_symbol] : error
>this[_symbol] = this[_symbol].bind(this) : () => Promise<void>
> : ^^^^^^^^^^^^^^^^^^^
>this[_symbol] : () => Promise<void>
> : ^^^^^^^^^^^^^^^^^^^
>this : this
> : ^^^^
>_symbol : unique symbol
> : ^^^^^^^^^^^^^
>this[_symbol].bind(this) : error
>this[_symbol].bind : error
>this[_symbol] : any
> : ^^^
>this[_symbol].bind(this) : () => Promise<void>
> : ^^^^^^^^^^^^^^^^^^^
>this[_symbol].bind : { <T>(this: T, thisArg: ThisParameterType<T>): OmitThisParameter<T>; <T, A extends any[], B extends any[], R>(this: (this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R; }
> : ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^ ^^^
>this[_symbol] : () => Promise<void>
> : ^^^^^^^^^^^^^^^^^^^
>this : this
> : ^^^^
>_symbol : unique symbol
> : ^^^^^^^^^^^^^
>bind : any
> : ^^^
>bind : { <T>(this: T, thisArg: ThisParameterType<T>): OmitThisParameter<T>; <T, A extends any[], B extends any[], R>(this: (this: T, ...args: [...A, ...B]) => R, thisArg: T, ...args: A): (...args: B) => R; }
> : ^^^ ^^ ^^ ^^ ^^ ^^^ ^^^ ^^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^^^^ ^^ ^^^ ^^^
>this : this
> : ^^^^
}
async [_symbol]() { }
>[_symbol] : error
>[_symbol] : () => Promise<void>
> : ^^^^^^^^^^^^^^^^^^^
>_symbol : unique symbol
> : ^^^^^^^^^^^^^
}

View File

@@ -0,0 +1,31 @@
// @strict: true
// @target: esnext
// @lib: esnext
// @declaration: true
// @outDir: dist
// @checkJs: true
// @allowJs: true
// @filename: index.js
// https://github.com/microsoft/TypeScript/issues/60590
export const kBar = Symbol("bar");
export class foo0 {
/**
* @protected
* @type {null | string}
*/
[kBar] = null;
get bar() {
return this[kBar];
}
/**
* @type {string}
*/
set bar(value) {
this[kBar] = value;
}
}

View File

@@ -0,0 +1,23 @@
// @strict: true
// @target: esnext
// @lib: esnext
// @declaration: true
// @outDir: dist
// @checkJs: true
// @allowJs: true
// @filename: index.js
const prop = 'prop';
export class foo1 {
constructor() {
this[prop] = 'bar'
}
/**
* @protected
* @type {string}
*/
[prop] = 'baz';
}

View File

@@ -0,0 +1,23 @@
// @strict: true
// @target: esnext
// @lib: esnext
// @declaration: true
// @outDir: dist
// @checkJs: true
// @allowJs: true
// @filename: index.js
const prop = 'prop';
export class foo2 {
constructor() {
this[prop] = 12;
}
/**
* @protected
* @type {string}
*/
prop = 'baz';
}