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>
This commit is contained in:
Mateusz Burzyński 2023-11-30 16:02:48 +01:00 committed by GitHub
parent 0a87761521
commit f834133fe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 8 deletions

View File

@ -5526,6 +5526,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getMergedSymbol(symbol.parent && getLateBoundSymbol(symbol.parent));
}
function getFunctionExpressionParentSymbolOrSymbol(symbol: Symbol) {
return symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression
? getSymbolOfNode(symbol.valueDeclaration.parent) || symbol
: symbol;
}
function getAlternativeContainingModules(symbol: Symbol, enclosingDeclaration: Node): Symbol[] {
const containingFile = getSourceFileOfNode(enclosingDeclaration);
const id = getNodeId(containingFile);
@ -11236,11 +11242,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
if (symbol.parent?.valueDeclaration) {
const typeNode = getEffectiveTypeAnnotationNode(symbol.parent.valueDeclaration);
if (typeNode) {
const annotationSymbol = getPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName);
if (annotationSymbol) {
return getNonMissingTypeOfSymbol(annotationSymbol);
const possiblyAnnotatedSymbol = getFunctionExpressionParentSymbolOrSymbol(symbol.parent);
if (possiblyAnnotatedSymbol.valueDeclaration) {
const typeNode = getEffectiveTypeAnnotationNode(possiblyAnnotatedSymbol.valueDeclaration);
if (typeNode) {
const annotationSymbol = getPropertyOfType(getTypeFromTypeNode(typeNode), symbol.escapedName);
if (annotationSymbol) {
return getNonMissingTypeOfSymbol(annotationSymbol);
}
}
}
}
@ -12932,9 +12941,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
}
const assignments = (symbol.valueDeclaration?.kind === SyntaxKind.ArrowFunction || symbol.valueDeclaration?.kind === SyntaxKind.FunctionExpression) &&
getSymbolOfNode(symbol.valueDeclaration.parent)?.assignmentDeclarationMembers ||
symbol.assignmentDeclarationMembers;
const assignments = getFunctionExpressionParentSymbolOrSymbol(symbol).assignmentDeclarationMembers;
if (assignments) {
const decls = arrayFrom(assignments.values());

View File

@ -0,0 +1,42 @@
//// [tests/cases/compiler/expandoFunctionExpressionsWithDynamicNames2.ts] ////
=== expandoFunctionExpressionsWithDynamicNames2.ts ===
const mySymbol = Symbol();
>mySymbol : Symbol(mySymbol, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 5))
>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, --, --))
interface Foo {
>Foo : Symbol(Foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 26))
(): void;
[mySymbol]: true;
>[mySymbol] : Symbol(Foo[mySymbol], Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 2, 11))
>mySymbol : Symbol(mySymbol, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 5))
}
const foo: Foo = () => {};
>foo : Symbol(foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 26))
>Foo : Symbol(Foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 26))
foo[mySymbol] = true;
>foo : Symbol(foo, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 5, 26))
>mySymbol : Symbol(mySymbol, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 0, 5))
interface Bar {
>Bar : Symbol(Bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 6, 21))
(): void;
test: true;
>test : Symbol(Bar.test, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 9, 11))
}
const t = "test" as const;
>t : Symbol(t, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 12, 5))
>const : Symbol(const)
const bar: Bar = () => {};
>bar : Symbol(bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 26))
>Bar : Symbol(Bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 6, 21))
bar[t] = true;
>bar : Symbol(bar, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 5), Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 13, 26))
>t : Symbol(t, Decl(expandoFunctionExpressionsWithDynamicNames2.ts, 12, 5))

View File

@ -0,0 +1,48 @@
//// [tests/cases/compiler/expandoFunctionExpressionsWithDynamicNames2.ts] ////
=== expandoFunctionExpressionsWithDynamicNames2.ts ===
const mySymbol = Symbol();
>mySymbol : unique symbol
>Symbol() : unique symbol
>Symbol : SymbolConstructor
interface Foo {
(): void;
[mySymbol]: true;
>[mySymbol] : true
>mySymbol : unique symbol
>true : true
}
const foo: Foo = () => {};
>foo : Foo
>() => {} : { (): void; [mySymbol]: true; }
foo[mySymbol] = true;
>foo[mySymbol] = true : true
>foo[mySymbol] : true
>foo : Foo
>mySymbol : unique symbol
>true : true
interface Bar {
(): void;
test: true;
>test : true
>true : true
}
const t = "test" as const;
>t : "test"
>"test" as const : "test"
>"test" : "test"
const bar: Bar = () => {};
>bar : Bar
>() => {} : { (): void; test: true; }
bar[t] = true;
>bar[t] = true : true
>bar[t] : true
>bar : Bar
>t : "test"
>true : true

View File

@ -0,0 +1,19 @@
// @strict: true
// @lib: esnext
// @noEmit: true
const mySymbol = Symbol();
interface Foo {
(): void;
[mySymbol]: true;
}
const foo: Foo = () => {};
foo[mySymbol] = true;
interface Bar {
(): void;
test: true;
}
const t = "test" as const;
const bar: Bar = () => {};
bar[t] = true;