mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(language-service): get quick info at local var location to align with TS semantics and support type narrowing
Previously, the Language Service fetched Quick Info and definitions for template variables (such as `@let` declarations) using mapping to their `initializerLocation` (the right-hand side expression). This aggressively bubbled the type, JSDoc, and definition identity of the initializer backwards onto the variable itself. This approach had two flaws: 1. It broke type narrowing because the LS read the original un-narrowed type from the source expression rather than the type of the narrowed intermediate variable in the Type Check Block. 2. It deviated from native TypeScript semantics, where a local `let` binding (`let address = hero.address`) does not inherit the docstrings or `(property)` kind of its initializer, acting solely as a local inferred variable. By using `localVarLocation` rather than `initializerLocation` for LetDeclaration Quick Info and Type Definitions, these intermediate variables now properly preserve type narrowing within templates and flawlessly match the standard behavior expected of TypeScript block variables. `VariableSymbol.initializerLocation` is retained solely to map the value spans of structural directive contexts (e.g., `exportAs` strings). fixes #65491
This commit is contained in:
committed by
Andrew Scott
parent
c15e3a005d
commit
75ac120493
@@ -274,11 +274,6 @@ export interface LetDeclarationSymbol {
|
||||
* The location in the shim file for the identifier of the `@let` declaration.
|
||||
*/
|
||||
localVarLocation: TcbLocation;
|
||||
|
||||
/**
|
||||
* The location in the shim file of the `@let` declaration's initializer expression.
|
||||
*/
|
||||
initializerLocation: TcbLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -646,9 +646,9 @@ export class SymbolBuilder {
|
||||
return {
|
||||
tsType: nodeValueSymbol.tsType,
|
||||
tsSymbol: nodeValueSymbol.tsSymbol,
|
||||
initializerLocation: nodeValueSymbol.tcbLocation,
|
||||
kind: SymbolKind.Variable,
|
||||
declaration: variable,
|
||||
initializerLocation: nodeValueSymbol.tcbLocation,
|
||||
localVarLocation: {
|
||||
tcbPath: this.tcbPath,
|
||||
isShimFile: this.tcbIsShim,
|
||||
@@ -727,7 +727,7 @@ export class SymbolBuilder {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nodeValueSymbol = this.getSymbolOfTsNode(node.initializer!);
|
||||
const nodeValueSymbol = this.getSymbolOfTsNode(node.name);
|
||||
|
||||
if (nodeValueSymbol === null) {
|
||||
return null;
|
||||
@@ -736,7 +736,6 @@ export class SymbolBuilder {
|
||||
return {
|
||||
tsType: nodeValueSymbol.tsType,
|
||||
tsSymbol: nodeValueSymbol.tsSymbol,
|
||||
initializerLocation: nodeValueSymbol.tcbLocation,
|
||||
kind: SymbolKind.LetDeclaration,
|
||||
declaration: decl,
|
||||
localVarLocation: {
|
||||
|
||||
-11
@@ -201,12 +201,6 @@ runInEachFileSystem(() => {
|
||||
assertVariableSymbol(symbol);
|
||||
expect(program.getTypeChecker().typeToString(symbol.tsType!)).toEqual('any');
|
||||
expect(symbol.declaration.name).toEqual('contextFoo');
|
||||
|
||||
// Ensure we can map the shim locations back to the template
|
||||
const initializerMapping = templateTypeChecker.getSourceMappingAtTcbLocation(
|
||||
symbol.initializerLocation,
|
||||
)!;
|
||||
expect(initializerMapping.span.toString()).toEqual('bar');
|
||||
const localVarMapping = templateTypeChecker.getSourceMappingAtTcbLocation(
|
||||
symbol.localVarLocation,
|
||||
)!;
|
||||
@@ -2025,11 +2019,6 @@ runInEachFileSystem(() => {
|
||||
expect(program.getTypeChecker().typeToString(symbol.tsType!)).toEqual('string');
|
||||
expect(symbol.declaration.name).toEqual('message');
|
||||
|
||||
// Ensure we can map the shim locations back to the template
|
||||
const initializerMapping = templateTypeChecker.getSourceMappingAtTcbLocation(
|
||||
symbol.initializerLocation,
|
||||
)!;
|
||||
expect(initializerMapping.span.toString()).toEqual(`'The value is ' + value`);
|
||||
const localVarMapping = templateTypeChecker.getSourceMappingAtTcbLocation(
|
||||
symbol.localVarLocation,
|
||||
)!;
|
||||
|
||||
Reference in New Issue
Block a user