Skip to content

Commit f834133

Browse files
Andaristsandersn
andauthored
Correctly resolve declared type for late bound property symbols of function expressions (#55357)
Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
1 parent 0a87761 commit f834133

4 files changed

Lines changed: 124 additions & 8 deletions

File tree

src/compiler/checker.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5526,6 +5526,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
55265526
return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent));
55275527
}
55285528

5529+
function getFunctionExpressionParentSymbolOrSymbol(symbol: Symbol) {
5530+
return symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression
5531+
? getSymbolOfNode(symbol.valueDeclaration.parent) || symbol
5532+
: symbol;
5533+
}
5534+
55295535
function getAlternativeContainingModules(symbol: Symbol, enclosingDeclaration: Node): Symbol[] {
55305536
const containingFile = getSourceFileOfNode(enclosingDeclaration);
55315537
const id = getNodeId(containingFile);
@@ -11236,11 +11242,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1123611242
}
1123711243
}
1123811244
if (symbol.parent?.valueDeclaration) {
11239-
const typeNode = getEffectiveTypeAnnotationNode(symbol.parent.valueDeclaration);
11240-
if (typeNode) {
11241-
const annotationSymbol = getPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName);
11242-
if (annotationSymbol) {
11243-
return getNonMissingTypeOfSymbol(annotationSymbol);
11245+
const possiblyAnnotatedSymbol = getFunctionExpressionParentSymbolOrSymbol(symbol.parent);
11246+
if (possiblyAnnotatedSymbol.valueDeclaration) {
11247+
const typeNode = getEffectiveTypeAnnotationNode(possiblyAnnotatedSymbol.valueDeclaration);
11248+
if (typeNode) {
11249+
const annotationSymbol = getPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName);
11250+
if (annotationSymbol) {
11251+
return getNonMissingTypeOfSymbol(annotationSymbol);
11252+
}
1124411253
}
1124511254
}
1124611255
}
@@ -12932,9 +12941,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1293212941
}
1293312942
}
1293412943
}
12935-
const assignments = (symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression) &&
12936-
getSymbolOfNode(symbol.valueDeclaration.parent)?.assignmentDeclarationMembers ||
12937-
symbol.assignmentDeclarationMembers;
12944+
const assignments = getFunctionExpressionParentSymbolOrSymbol(symbol).assignmentDeclarationMembers;
1293812945

1293912946
if (assignments) {
1294012947
const decls = arrayFrom(assignments.values());
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [tests/cases/compiler/expandoFunctionExpressionsWithDynamicNames2.ts] ////
2+
3+
=== expandoFunctionExpressionsWithDynamicNames2.ts ===
4+
const mySymbol = Symbol();
5+
>mySymbol : Symbol(mySymbol, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 5))
6+
>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, --, --))
7+
8+
interface Foo {
9+
>Foo : Symbol(Foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 26))
10+
11+
(): void;
12+
[mySymbol]: true;
13+
>[mySymbol] : Symbol(Foo[mySymbol], Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 2, 11))
14+
>mySymbol : Symbol(mySymbol, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 5))
15+
}
16+
const foo: Foo = () => {};
17+
>foo : Symbol(foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 26))
18+
>Foo : Symbol(Foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 26))
19+
20+
foo[mySymbol] = true;
21+
>foo : Symbol(foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 26))
22+
>mySymbol : Symbol(mySymbol, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 5))
23+
24+
interface Bar {
25+
>Bar : Symbol(Bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 6, 21))
26+
27+
(): void;
28+
test: true;
29+
>test : Symbol(Bar.test, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 9, 11))
30+
}
31+
const t = "test" as const;
32+
>t : Symbol(t, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 12, 5))
33+
>const : Symbol(const)
34+
35+
const bar: Bar = () => {};
36+
>bar : Symbol(bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 26))
37+
>Bar : Symbol(Bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 6, 21))
38+
39+
bar[t] = true;
40+
>bar : Symbol(bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 26))
41+
>t : Symbol(t, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 12, 5))
42+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//// [tests/cases/compiler/expandoFunctionExpressionsWithDynamicNames2.ts] ////
2+
3+
=== expandoFunctionExpressionsWithDynamicNames2.ts ===
4+
const mySymbol = Symbol();
5+
>mySymbol : unique symbol
6+
>Symbol() : unique symbol
7+
>Symbol : SymbolConstructor
8+
9+
interface Foo {
10+
(): void;
11+
[mySymbol]: true;
12+
>[mySymbol] : true
13+
>mySymbol : unique symbol
14+
>true : true
15+
}
16+
const foo: Foo = () => {};
17+
>foo : Foo
18+
>() => {} : { (): void; [mySymbol]: true; }
19+
20+
foo[mySymbol] = true;
21+
>foo[mySymbol] = true : true
22+
>foo[mySymbol] : true
23+
>foo : Foo
24+
>mySymbol : unique symbol
25+
>true : true
26+
27+
interface Bar {
28+
(): void;
29+
test: true;
30+
>test : true
31+
>true : true
32+
}
33+
const t = "test" as const;
34+
>t : "test"
35+
>"test" as const : "test"
36+
>"test" : "test"
37+
38+
const bar: Bar = () => {};
39+
>bar : Bar
40+
>() => {} : { (): void; test: true; }
41+
42+
bar[t] = true;
43+
>bar[t] = true : true
44+
>bar[t] : true
45+
>bar : Bar
46+
>t : "test"
47+
>true : true
48+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @strict: true
2+
// @lib: esnext
3+
// @noEmit: true
4+
5+
const mySymbol = Symbol();
6+
interface Foo {
7+
(): void;
8+
[mySymbol]: true;
9+
}
10+
const foo: Foo = () => {};
11+
foo[mySymbol] = true;
12+
13+
interface Bar {
14+
(): void;
15+
test: true;
16+
}
17+
const t = "test" as const;
18+
const bar: Bar = () => {};
19+
bar[t] = true;

0 commit comments

Comments
 (0)