Skip to content

Commit a00b324

Browse files
Fix serialization of accessor types in declaration files. (#61392)
1 parent 0aac720 commit a00b324

14 files changed

+518
-32
lines changed

src/compiler/checker.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -6136,10 +6136,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
61366136
serializeExistingTypeNode(context, typeNode, addUndefined) {
61376137
return serializeExistingTypeNode(context as NodeBuilderContext, typeNode, !!addUndefined);
61386138
},
6139-
serializeReturnTypeForSignature(syntacticContext, signatureDeclaration) {
6139+
serializeReturnTypeForSignature(syntacticContext, signatureDeclaration, symbol) {
61406140
const context = syntacticContext as NodeBuilderContext;
61416141
const signature = getSignatureFromDeclaration(signatureDeclaration);
6142-
const returnType = context.enclosingSymbolTypes.get(getSymbolId(getSymbolOfDeclaration(signatureDeclaration))) ?? instantiateType(getReturnTypeOfSignature(signature), context.mapper);
6142+
symbol ??= getSymbolOfDeclaration(signatureDeclaration);
6143+
const returnType = context.enclosingSymbolTypes.get(getSymbolId(symbol)) ?? instantiateType(getReturnTypeOfSignature(signature), context.mapper);
61436144
return serializeInferredReturnTypeForSignature(context, signature, returnType);
61446145
},
61456146
serializeTypeOfExpression(syntacticContext, expr) {
@@ -6153,7 +6154,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
61536154
symbol ??= getSymbolOfDeclaration(declaration);
61546155
let type = context.enclosingSymbolTypes?.get(getSymbolId(symbol));
61556156
if (type === undefined) {
6156-
type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
6157+
type = symbol.flags & SymbolFlags.Accessor && declaration.kind === SyntaxKind.SetAccessor ? instantiateType(getWriteTypeOfSymbol(symbol), context.mapper) :
6158+
symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.Signature))
61576159
? instantiateType(getWidenedLiteralType(getTypeOfSymbol(symbol)), context.mapper)
61586160
: errorType;
61596161
}
@@ -7386,12 +7388,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
73867388
if (propertySymbol.flags & SymbolFlags.Accessor) {
73877389
const writeType = getWriteTypeOfSymbol(propertySymbol);
73887390
if (propertyType !== writeType && !isErrorType(propertyType) && !isErrorType(writeType)) {
7391+
const symbolMapper = getSymbolLinks(propertySymbol).mapper;
73897392
const getterDeclaration = getDeclarationOfKind<GetAccessorDeclaration>(propertySymbol, SyntaxKind.GetAccessor)!;
73907393
const getterSignature = getSignatureFromDeclaration(getterDeclaration);
73917394
typeElements.push(
73927395
setCommentRange(
73937396
context,
7394-
signatureToSignatureDeclarationHelper(getterSignature, SyntaxKind.GetAccessor, context, { name: propertyName }) as GetAccessorDeclaration,
7397+
signatureToSignatureDeclarationHelper(symbolMapper ? instantiateSignature(getterSignature, symbolMapper) : getterSignature, SyntaxKind.GetAccessor, context, { name: propertyName }) as GetAccessorDeclaration,
73957398
getterDeclaration,
73967399
),
73977400
);
@@ -7400,7 +7403,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
74007403
typeElements.push(
74017404
setCommentRange(
74027405
context,
7403-
signatureToSignatureDeclarationHelper(setterSignature, SyntaxKind.SetAccessor, context, { name: propertyName }) as SetAccessorDeclaration,
7406+
signatureToSignatureDeclarationHelper(symbolMapper ? instantiateSignature(setterSignature, symbolMapper) : setterSignature, SyntaxKind.SetAccessor, context, { name: propertyName }) as SetAccessorDeclaration,
74047407
setterDeclaration,
74057408
),
74067409
);
@@ -8665,6 +8668,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86658668
const addUndefinedForParameter = declaration && (isParameter(declaration) || isJSDocParameterTag(declaration)) && requiresAddingImplicitUndefined(declaration, context.enclosingDeclaration);
86668669
const decl = declaration ?? symbol.valueDeclaration ?? getDeclarationWithTypeAnnotation(symbol) ?? symbol.declarations?.[0];
86678670
if (decl) {
8671+
const restore = addSymbolTypeToContext(context, symbol, type);
86688672
if (isAccessor(decl)) {
86698673
result = syntacticNodeBuilder.serializeTypeOfAccessor(decl, symbol, context);
86708674
}
@@ -8673,10 +8677,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86738677
&& !nodeIsSynthesized(decl)
86748678
&& !(getObjectFlags(type) & ObjectFlags.RequiresWidening)
86758679
) {
8676-
const restore = addSymbolTypeToContext(context, symbol, type);
86778680
result = syntacticNodeBuilder.serializeTypeOfDeclaration(decl, symbol, context);
8678-
restore();
86798681
}
8682+
restore();
86808683
}
86818684
if (!result) {
86828685
if (addUndefinedForParameter) {

src/compiler/expressionToTypeNode.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ export function createSyntacticTypeNodeBuilder(
763763
return withNewScope(context, node, () => serializeTypeAnnotationOfDeclaration(accessorType, context, node, symbol) ?? inferTypeOfDeclaration(node, symbol, context));
764764
}
765765
if (accessorDeclarations.getAccessor) {
766-
return withNewScope(context, accessorDeclarations.getAccessor, () => createReturnFromSignature(accessorDeclarations.getAccessor!, /*symbol*/ undefined, context));
766+
return withNewScope(context, accessorDeclarations.getAccessor, () => createReturnFromSignature(accessorDeclarations.getAccessor!, symbol, context));
767767
}
768768
return undefined;
769769
}
@@ -854,14 +854,14 @@ export function createSyntacticTypeNodeBuilder(
854854
return resolver.serializeTypeOfExpression(context, node) ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
855855
}
856856

857-
function inferReturnTypeOfSignatureSignature(node: SignatureDeclaration | JSDocSignature, context: SyntacticTypeNodeBuilderContext, reportFallback: boolean) {
857+
function inferReturnTypeOfSignatureSignature(node: SignatureDeclaration | JSDocSignature, context: SyntacticTypeNodeBuilderContext, symbol: Symbol | undefined, reportFallback: boolean) {
858858
if (reportFallback) {
859859
context.tracker.reportInferenceFallback(node);
860860
}
861861
if (context.noInferenceFallback === true) {
862862
return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
863863
}
864-
return resolver.serializeReturnTypeForSignature(context, node) ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
864+
return resolver.serializeReturnTypeForSignature(context, node, symbol) ?? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
865865
}
866866

867867
function inferAccessorType(node: GetAccessorDeclaration | SetAccessorDeclaration, allAccessors: AllAccessorDeclarations, context: SyntacticTypeNodeBuilderContext, symbol: Symbol | undefined, reportFallback: boolean = true): TypeNode | undefined {
@@ -1276,7 +1276,7 @@ export function createSyntacticTypeNodeBuilder(
12761276
else if (isValueSignatureDeclaration(fn)) {
12771277
returnType = typeFromSingleReturnExpression(fn, context);
12781278
}
1279-
return returnType.type !== undefined ? returnType.type : inferReturnTypeOfSignatureSignature(fn, context, reportFallback && returnType.reportFallback && !returnTypeNode);
1279+
return returnType.type !== undefined ? returnType.type : inferReturnTypeOfSignatureSignature(fn, context, symbol, reportFallback && returnType.reportFallback && !returnTypeNode);
12801280
}
12811281

12821282
function typeFromSingleReturnExpression(declaration: FunctionLikeDeclaration | undefined, context: SyntacticTypeNodeBuilderContext): SyntacticResult {

src/compiler/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10553,7 +10553,7 @@ export interface SyntacticTypeNodeBuilderResolver {
1055310553
isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean;
1055410554
isEntityNameVisible(context: SyntacticTypeNodeBuilderContext, entityName: EntityNameOrEntityNameExpression, shouldComputeAliasToMakeVisible?: boolean): SymbolVisibilityResult;
1055510555
serializeExistingTypeNode(context: SyntacticTypeNodeBuilderContext, node: TypeNode, addUndefined?: boolean): TypeNode | undefined;
10556-
serializeReturnTypeForSignature(context: SyntacticTypeNodeBuilderContext, signatureDeclaration: SignatureDeclaration | JSDocSignature): TypeNode | undefined;
10556+
serializeReturnTypeForSignature(context: SyntacticTypeNodeBuilderContext, signatureDeclaration: SignatureDeclaration | JSDocSignature, symbol: Symbol | undefined): TypeNode | undefined;
1055710557
serializeTypeOfExpression(context: SyntacticTypeNodeBuilderContext, expr: Expression): TypeNode;
1055810558
serializeTypeOfDeclaration(context: SyntacticTypeNodeBuilderContext, node: HasInferredType | GetAccessorDeclaration | SetAccessorDeclaration, symbol: Symbol | undefined): TypeNode | undefined;
1055910559
serializeNameOfParameter(context: SyntacticTypeNodeBuilderContext, parameter: ParameterDeclaration): BindingName | string;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//// [tests/cases/compiler/declarationEmitGenericTypeParamerSerialization.ts] ////
2+
3+
//// [declarationEmitGenericTypeParamerSerialization.ts]
4+
function wrapper<T>(value: T) {
5+
return {
6+
m() { return value; },
7+
get g() { return value; },
8+
}
9+
}
10+
11+
export const w = wrapper(0)
12+
13+
14+
//// [declarationEmitGenericTypeParamerSerialization.js]
15+
"use strict";
16+
Object.defineProperty(exports, "__esModule", { value: true });
17+
exports.w = void 0;
18+
function wrapper(value) {
19+
return {
20+
m: function () { return value; },
21+
get g() { return value; },
22+
};
23+
}
24+
exports.w = wrapper(0);
25+
26+
27+
//// [declarationEmitGenericTypeParamerSerialization.d.ts]
28+
export declare const w: {
29+
m(): number;
30+
readonly g: number;
31+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [tests/cases/compiler/declarationEmitGenericTypeParamerSerialization.ts] ////
2+
3+
=== declarationEmitGenericTypeParamerSerialization.ts ===
4+
function wrapper<T>(value: T) {
5+
>wrapper : Symbol(wrapper, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 0))
6+
>T : Symbol(T, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 17))
7+
>value : Symbol(value, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 20))
8+
>T : Symbol(T, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 17))
9+
10+
return {
11+
m() { return value; },
12+
>m : Symbol(m, Decl(declarationEmitGenericTypeParamerSerialization.ts, 1, 10))
13+
>value : Symbol(value, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 20))
14+
15+
get g() { return value; },
16+
>g : Symbol(g, Decl(declarationEmitGenericTypeParamerSerialization.ts, 2, 28))
17+
>value : Symbol(value, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 20))
18+
}
19+
}
20+
21+
export const w = wrapper(0)
22+
>w : Symbol(w, Decl(declarationEmitGenericTypeParamerSerialization.ts, 7, 12))
23+
>wrapper : Symbol(wrapper, Decl(declarationEmitGenericTypeParamerSerialization.ts, 0, 0))
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//// [tests/cases/compiler/declarationEmitGenericTypeParamerSerialization.ts] ////
2+
3+
=== declarationEmitGenericTypeParamerSerialization.ts ===
4+
function wrapper<T>(value: T) {
5+
>wrapper : <T>(value: T) => { m(): T; readonly g: T; }
6+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7+
>value : T
8+
> : ^
9+
10+
return {
11+
>{ m() { return value; }, get g() { return value; }, } : { m(): T; readonly g: T; }
12+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
m() { return value; },
15+
>m : () => T
16+
> : ^^^^^^^
17+
>value : T
18+
> : ^
19+
20+
get g() { return value; },
21+
>g : T
22+
> : ^
23+
>value : T
24+
> : ^
25+
}
26+
}
27+
28+
export const w = wrapper(0)
29+
>w : { m(): number; readonly g: number; }
30+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
31+
>wrapper(0) : { m(): number; readonly g: number; }
32+
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
33+
>wrapper : <T>(value: T) => { m(): T; readonly g: T; }
34+
> : ^ ^^ ^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
>0 : 0
36+
> : ^
37+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//// [tests/cases/compiler/declarationEmitGenericTypeParamerSerialization2.ts] ////
2+
3+
//// [declarationEmitGenericTypeParamerSerialization2.ts]
4+
type ExpandRecursively<T> = {} & {
5+
[P in keyof T]: T[P]
6+
}
7+
8+
type G<T = string> = {
9+
get readonlyProperty(): T;
10+
field: T;
11+
method(p: T): T;
12+
fnField: (p: T) => T;
13+
set writeOnlyProperty(p: T);
14+
get property(): T;
15+
set property(p: T);
16+
get divergentProperty(): string | T;
17+
set divergentProperty(p: number | T);
18+
};
19+
20+
export const x = (() => null! as ExpandRecursively<G>)();
21+
22+
23+
function makeV() {
24+
type X<T> = {
25+
get readonlyProperty(): T;
26+
field: T;
27+
method(p: T): T;
28+
fnField: (p: T) => T;
29+
set writeOnlyProperty(p: T);
30+
get property(): T;
31+
set property(p: T);
32+
get divergentProperty(): string | T;
33+
set divergentProperty(p: number | T);
34+
}
35+
return null! as X<number>
36+
}
37+
38+
export const v = makeV();
39+
40+
41+
//// [declarationEmitGenericTypeParamerSerialization2.js]
42+
"use strict";
43+
Object.defineProperty(exports, "__esModule", { value: true });
44+
exports.v = exports.x = void 0;
45+
exports.x = (function () { return null; })();
46+
function makeV() {
47+
return null;
48+
}
49+
exports.v = makeV();
50+
51+
52+
//// [declarationEmitGenericTypeParamerSerialization2.d.ts]
53+
export declare const x: {
54+
readonly readonlyProperty: string;
55+
field: string;
56+
method: (p: string) => string;
57+
fnField: (p: string) => string;
58+
writeOnlyProperty: string;
59+
property: string;
60+
divergentProperty: string;
61+
};
62+
export declare const v: {
63+
readonly readonlyProperty: number;
64+
field: number;
65+
method(p: number): number;
66+
fnField: (p: number) => number;
67+
writeOnlyProperty: number;
68+
property: number;
69+
get divergentProperty(): string | number;
70+
set divergentProperty(p: number);
71+
};

0 commit comments

Comments
 (0)