diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index 7bced48353b82..a8757512f4194 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -47,6 +47,7 @@ import { ModeAwareCache, ModuleResolutionCache, moduleResolutionNameAndModeGetter, + Mutable, mutateMap, noopFileWatcher, normalizePath, @@ -556,7 +557,7 @@ function resolveModuleNameUsingGlobalCache( ); if (resolvedModule) { // Modify existing resolution so its saved in the directory cache as well - (primaryResult.resolvedModule as any) = resolvedModule; + (primaryResult as Mutable).resolvedModule = resolvedModule; primaryResult.failedLookupLocations = updateResolutionField(primaryResult.failedLookupLocations, failedLookupLocations); primaryResult.affectingLocations = updateResolutionField(primaryResult.affectingLocations, affectingLocations); primaryResult.resolutionDiagnostics = updateResolutionField(primaryResult.resolutionDiagnostics, resolutionDiagnostics); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4687bb8796fad..a78643db4c0c6 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4801,6 +4801,8 @@ function getAssignmentTarget(node: Node): AssignmentTarget | undefined { case SyntaxKind.ArrayLiteralExpression: case SyntaxKind.SpreadElement: case SyntaxKind.NonNullExpression: + case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.AsExpression: node = parent; break; case SyntaxKind.SpreadAssignment: diff --git a/tests/baselines/reference/classNameReferencesInStaticElements.errors.txt b/tests/baselines/reference/classNameReferencesInStaticElements.errors.txt new file mode 100644 index 0000000000000..43328c9e1f238 --- /dev/null +++ b/tests/baselines/reference/classNameReferencesInStaticElements.errors.txt @@ -0,0 +1,21 @@ +classNameReferencesInStaticElements.ts(12,2): error TS2629: Cannot assign to 'Foo' because it is a class. + + +==== classNameReferencesInStaticElements.ts (1 errors) ==== + // https://github.com/microsoft/TypeScript/issues/54607 + class Foo { + static { console.log(this, Foo) } + static x = () => { console.log(this, Foo) } + static y = function(this: unknown) { console.log(this, Foo) } + + #x() { console.log(Foo); } + x() { this.#x(); } + } + + const oldFoo = Foo; + (Foo as any) = null; + ~~~ +!!! error TS2629: Cannot assign to 'Foo' because it is a class. + oldFoo.x(); + oldFoo.y(); + new oldFoo().x(); \ No newline at end of file diff --git a/tests/baselines/reference/usedBeforeAssignedTypeAssertion.errors.txt b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.errors.txt new file mode 100644 index 0000000000000..90453e700831d --- /dev/null +++ b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.errors.txt @@ -0,0 +1,35 @@ +usedBeforeAssignedTypeAssertion.ts(28,12): error TS2454: Variable 'uninitialized' is used before being assigned. + + +==== usedBeforeAssignedTypeAssertion.ts (1 errors) ==== + // Test case for type assertion (angle bracket syntax) - assignment should not error + function testTypeAssertion() { + let x: number; + (x) = 42; // Should not error - this is an assignment + } + + // Test case for 'as' expression - assignment should not error + function testAsExpression() { + let y: number; + (y as any) = 42; // Should not error - this is an assignment + } + + // Test case for parenthesized expression (should already work) + function testParentheses() { + let z: number; + (z) = 42; // Should not error - this is an assignment + } + + // Test case with nested type assertions + function testNested() { + let nested: any; + ((nested as any) as unknown) = "test"; // Should not error + } + + // Test cases that should still produce errors for proper context + function shouldStillError() { + let uninitialized: number; + return uninitialized; // Should error - never assigned + ~~~~~~~~~~~~~ +!!! error TS2454: Variable 'uninitialized' is used before being assigned. + } \ No newline at end of file diff --git a/tests/baselines/reference/usedBeforeAssignedTypeAssertion.js b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.js new file mode 100644 index 0000000000000..1e72ae11dbd7d --- /dev/null +++ b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.js @@ -0,0 +1,60 @@ +//// [tests/cases/compiler/usedBeforeAssignedTypeAssertion.ts] //// + +//// [usedBeforeAssignedTypeAssertion.ts] +// Test case for type assertion (angle bracket syntax) - assignment should not error +function testTypeAssertion() { + let x: number; + (x) = 42; // Should not error - this is an assignment +} + +// Test case for 'as' expression - assignment should not error +function testAsExpression() { + let y: number; + (y as any) = 42; // Should not error - this is an assignment +} + +// Test case for parenthesized expression (should already work) +function testParentheses() { + let z: number; + (z) = 42; // Should not error - this is an assignment +} + +// Test case with nested type assertions +function testNested() { + let nested: any; + ((nested as any) as unknown) = "test"; // Should not error +} + +// Test cases that should still produce errors for proper context +function shouldStillError() { + let uninitialized: number; + return uninitialized; // Should error - never assigned +} + +//// [usedBeforeAssignedTypeAssertion.js] +"use strict"; +// Test case for type assertion (angle bracket syntax) - assignment should not error +function testTypeAssertion() { + var x; + x = 42; // Should not error - this is an assignment +} +// Test case for 'as' expression - assignment should not error +function testAsExpression() { + var y; + y = 42; // Should not error - this is an assignment +} +// Test case for parenthesized expression (should already work) +function testParentheses() { + var z; + (z) = 42; // Should not error - this is an assignment +} +// Test case with nested type assertions +function testNested() { + var nested; + nested = "test"; // Should not error +} +// Test cases that should still produce errors for proper context +function shouldStillError() { + var uninitialized; + return uninitialized; // Should error - never assigned +} diff --git a/tests/baselines/reference/usedBeforeAssignedTypeAssertion.symbols b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.symbols new file mode 100644 index 0000000000000..e9ebf35a4acd0 --- /dev/null +++ b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.symbols @@ -0,0 +1,57 @@ +//// [tests/cases/compiler/usedBeforeAssignedTypeAssertion.ts] //// + +=== usedBeforeAssignedTypeAssertion.ts === +// Test case for type assertion (angle bracket syntax) - assignment should not error +function testTypeAssertion() { +>testTypeAssertion : Symbol(testTypeAssertion, Decl(usedBeforeAssignedTypeAssertion.ts, 0, 0)) + + let x: number; +>x : Symbol(x, Decl(usedBeforeAssignedTypeAssertion.ts, 2, 7)) + + (x) = 42; // Should not error - this is an assignment +>x : Symbol(x, Decl(usedBeforeAssignedTypeAssertion.ts, 2, 7)) +} + +// Test case for 'as' expression - assignment should not error +function testAsExpression() { +>testAsExpression : Symbol(testAsExpression, Decl(usedBeforeAssignedTypeAssertion.ts, 4, 1)) + + let y: number; +>y : Symbol(y, Decl(usedBeforeAssignedTypeAssertion.ts, 8, 7)) + + (y as any) = 42; // Should not error - this is an assignment +>y : Symbol(y, Decl(usedBeforeAssignedTypeAssertion.ts, 8, 7)) +} + +// Test case for parenthesized expression (should already work) +function testParentheses() { +>testParentheses : Symbol(testParentheses, Decl(usedBeforeAssignedTypeAssertion.ts, 10, 1)) + + let z: number; +>z : Symbol(z, Decl(usedBeforeAssignedTypeAssertion.ts, 14, 7)) + + (z) = 42; // Should not error - this is an assignment +>z : Symbol(z, Decl(usedBeforeAssignedTypeAssertion.ts, 14, 7)) +} + +// Test case with nested type assertions +function testNested() { +>testNested : Symbol(testNested, Decl(usedBeforeAssignedTypeAssertion.ts, 16, 1)) + + let nested: any; +>nested : Symbol(nested, Decl(usedBeforeAssignedTypeAssertion.ts, 20, 7)) + + ((nested as any) as unknown) = "test"; // Should not error +>nested : Symbol(nested, Decl(usedBeforeAssignedTypeAssertion.ts, 20, 7)) +} + +// Test cases that should still produce errors for proper context +function shouldStillError() { +>shouldStillError : Symbol(shouldStillError, Decl(usedBeforeAssignedTypeAssertion.ts, 22, 1)) + + let uninitialized: number; +>uninitialized : Symbol(uninitialized, Decl(usedBeforeAssignedTypeAssertion.ts, 26, 7)) + + return uninitialized; // Should error - never assigned +>uninitialized : Symbol(uninitialized, Decl(usedBeforeAssignedTypeAssertion.ts, 26, 7)) +} diff --git a/tests/baselines/reference/usedBeforeAssignedTypeAssertion.types b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.types new file mode 100644 index 0000000000000..9b38ec1898dbe --- /dev/null +++ b/tests/baselines/reference/usedBeforeAssignedTypeAssertion.types @@ -0,0 +1,106 @@ +//// [tests/cases/compiler/usedBeforeAssignedTypeAssertion.ts] //// + +=== usedBeforeAssignedTypeAssertion.ts === +// Test case for type assertion (angle bracket syntax) - assignment should not error +function testTypeAssertion() { +>testTypeAssertion : () => void +> : ^^^^^^^^^^ + + let x: number; +>x : number +> : ^^^^^^ + + (x) = 42; // Should not error - this is an assignment +>(x) = 42 : 42 +> : ^^ +>(x) : any +> : ^^^ +>x : any +> : ^^^ +>x : number +> : ^^^^^^ +>42 : 42 +> : ^^ +} + +// Test case for 'as' expression - assignment should not error +function testAsExpression() { +>testAsExpression : () => void +> : ^^^^^^^^^^ + + let y: number; +>y : number +> : ^^^^^^ + + (y as any) = 42; // Should not error - this is an assignment +>(y as any) = 42 : 42 +> : ^^ +>(y as any) : any +> : ^^^ +>y as any : any +> : ^^^ +>y : number +> : ^^^^^^ +>42 : 42 +> : ^^ +} + +// Test case for parenthesized expression (should already work) +function testParentheses() { +>testParentheses : () => void +> : ^^^^^^^^^^ + + let z: number; +>z : number +> : ^^^^^^ + + (z) = 42; // Should not error - this is an assignment +>(z) = 42 : 42 +> : ^^ +>(z) : number +> : ^^^^^^ +>z : number +> : ^^^^^^ +>42 : 42 +> : ^^ +} + +// Test case with nested type assertions +function testNested() { +>testNested : () => void +> : ^^^^^^^^^^ + + let nested: any; +>nested : any +> : ^^^ + + ((nested as any) as unknown) = "test"; // Should not error +>((nested as any) as unknown) = "test" : "test" +> : ^^^^^^ +>((nested as any) as unknown) : unknown +> : ^^^^^^^ +>(nested as any) as unknown : unknown +> : ^^^^^^^ +>(nested as any) : any +> : ^^^ +>nested as any : any +> : ^^^ +>nested : any +> : ^^^ +>"test" : "test" +> : ^^^^^^ +} + +// Test cases that should still produce errors for proper context +function shouldStillError() { +>shouldStillError : () => number +> : ^^^^^^^^^^^^ + + let uninitialized: number; +>uninitialized : number +> : ^^^^^^ + + return uninitialized; // Should error - never assigned +>uninitialized : number +> : ^^^^^^ +} diff --git a/tests/cases/compiler/usedBeforeAssignedTypeAssertion.ts b/tests/cases/compiler/usedBeforeAssignedTypeAssertion.ts new file mode 100644 index 0000000000000..a5de18c18bc89 --- /dev/null +++ b/tests/cases/compiler/usedBeforeAssignedTypeAssertion.ts @@ -0,0 +1,31 @@ +// @strict: true + +// Test case for type assertion (angle bracket syntax) - assignment should not error +function testTypeAssertion() { + let x: number; + (x) = 42; // Should not error - this is an assignment +} + +// Test case for 'as' expression - assignment should not error +function testAsExpression() { + let y: number; + (y as any) = 42; // Should not error - this is an assignment +} + +// Test case for parenthesized expression (should already work) +function testParentheses() { + let z: number; + (z) = 42; // Should not error - this is an assignment +} + +// Test case with nested type assertions +function testNested() { + let nested: any; + ((nested as any) as unknown) = "test"; // Should not error +} + +// Test cases that should still produce errors for proper context +function shouldStillError() { + let uninitialized: number; + return uninitialized; // Should error - never assigned +} \ No newline at end of file