Skip to content

Commit 8c5a594

Browse files
dragomirtitiantypescript-bot
authored andcommitted
Fix serialization of accessor types in declaration files. (#61392)
1 parent beb69e4 commit 8c5a594

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
}
@@ -7383,12 +7385,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
73837385
if (propertySymbol.flags & SymbolFlags.Accessor) {
73847386
const writeType = getWriteTypeOfSymbol(propertySymbol);
73857387
if (propertyType !== writeType && !isErrorType(propertyType) && !isErrorType(writeType)) {
7388+
const symbolMapper = getSymbolLinks(propertySymbol).mapper;
73867389
const getterDeclaration = getDeclarationOfKind<GetAccessorDeclaration>(propertySymbol, SyntaxKind.GetAccessor)!;
73877390
const getterSignature = getSignatureFromDeclaration(getterDeclaration);
73887391
typeElements.push(
73897392
setCommentRange(
73907393
context,
7391-
signatureToSignatureDeclarationHelper(getterSignature, SyntaxKind.GetAccessor, context, { name: propertyName }) as GetAccessorDeclaration,
7394+
signatureToSignatureDeclarationHelper(symbolMapper ? instantiateSignature(getterSignature, symbolMapper) : getterSignature, SyntaxKind.GetAccessor, context, { name: propertyName }) as GetAccessorDeclaration,
73927395
getterDeclaration,
73937396
),
73947397
);
@@ -7397,7 +7400,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
73977400
typeElements.push(
73987401
setCommentRange(
73997402
context,
7400-
signatureToSignatureDeclarationHelper(setterSignature, SyntaxKind.SetAccessor, context, { name: propertyName }) as SetAccessorDeclaration,
7403+
signatureToSignatureDeclarationHelper(symbolMapper ? instantiateSignature(setterSignature, symbolMapper) : setterSignature, SyntaxKind.SetAccessor, context, { name: propertyName }) as SetAccessorDeclaration,
74017404
setterDeclaration,
74027405
),
74037406
);
@@ -8662,6 +8665,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86628665
const addUndefinedForParameter = declaration && (isParameter(declaration) || isJSDocParameterTag(declaration)) && requiresAddingImplicitUndefined(declaration, context.enclosingDeclaration);
86638666
const decl = declaration ?? symbol.valueDeclaration ?? getDeclarationWithTypeAnnotation(symbol) ?? symbol.declarations?.[0];
86648667
if (decl) {
8668+
const restore = addSymbolTypeToContext(context, symbol, type);
86658669
if (isAccessor(decl)) {
86668670
result = syntacticNodeBuilder.serializeTypeOfAccessor(decl, symbol, context);
86678671
}
@@ -8670,10 +8674,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
86708674
&& !nodeIsSynthesized(decl)
86718675
&& !(getObjectFlags(type) & ObjectFlags.RequiresWidening)
86728676
) {
8673-
const restore = addSymbolTypeToContext(context, symbol, type);
86748677
result = syntacticNodeBuilder.serializeTypeOfDeclaration(decl, symbol, context);
8675-
restore();
86768678
}
8679+
restore();
86778680
}
86788681
if (!result) {
86798682
if (addUndefinedForParameter) {

src/compiler/expressionToTypeNode.ts

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

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

868868
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)