Skip to content

Commit 360958e

Browse files
authored
JSDoc declaration emit should reuse input nodes where possible when serializing typedefs (#41760)
* JSDoc declaration emit should reuse input nodes where possible when serializing typedefs * Style comments
1 parent 3c7ac73 commit 360958e

21 files changed

+488
-92
lines changed

src/compiler/checker.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5961,6 +5961,18 @@ namespace ts {
59615961
return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node);
59625962
}
59635963
if (isLiteralImportTypeNode(node)) {
5964+
const nodeSymbol = getNodeLinks(node).resolvedSymbol;
5965+
if (isInJSDoc(node) &&
5966+
nodeSymbol &&
5967+
(
5968+
// The import type resolved using jsdoc fallback logic
5969+
(!node.isTypeOf && !(nodeSymbol.flags & SymbolFlags.Type)) ||
5970+
// The import type had type arguments autofilled by js fallback logic
5971+
!(length(node.typeArguments) >= getMinTypeArgumentCount(getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(nodeSymbol)))
5972+
)
5973+
) {
5974+
return setOriginalNode(typeToTypeNodeHelper(getTypeFromTypeNode(node), context), node);
5975+
}
59645976
return factory.updateImportTypeNode(
59655977
node,
59665978
factory.updateLiteralTypeNode(node.argument, rewriteModuleSpecifier(node, node.argument.literal)),
@@ -6536,8 +6548,12 @@ namespace ts {
65366548
const commentText = jsdocAliasDecl ? jsdocAliasDecl.comment || jsdocAliasDecl.parent.comment : undefined;
65376549
const oldFlags = context.flags;
65386550
context.flags |= NodeBuilderFlags.InTypeAlias;
6551+
const typeNode = jsdocAliasDecl && jsdocAliasDecl.typeExpression
6552+
&& isJSDocTypeExpression(jsdocAliasDecl.typeExpression)
6553+
&& serializeExistingTypeNode(context, jsdocAliasDecl.typeExpression.type, includePrivateSymbol, bundled)
6554+
|| typeToTypeNodeHelper(aliasType, context);
65396555
addResult(setSyntheticLeadingComments(
6540-
factory.createTypeAliasDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, getInternalSymbolName(symbol, symbolName), typeParamDecls, typeToTypeNodeHelper(aliasType, context)),
6556+
factory.createTypeAliasDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, getInternalSymbolName(symbol, symbolName), typeParamDecls, typeNode),
65416557
!commentText ? [] : [{ kind: SyntaxKind.MultiLineCommentTrivia, text: "*\n * " + commentText.replace(/\n/g, "\n * ") + "\n ", pos: -1, end: -1, hasTrailingNewLine: true }]
65426558
), modifierFlags);
65436559
context.flags = oldFlags;

tests/baselines/reference/jsDeclarationsFunctionClassesCjsExportAssignment.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ type Input = {
231231
/**
232232
* Imports
233233
*/
234-
type HookHandler = (arg: Context) => void;
234+
type HookHandler = import("./hook").HookHandler;
235235
/**
236236
* State type definition
237237
*/

tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export {testFn, testFnTypes};
5555

5656
//// [file.d.ts]
5757
export namespace myTypes {
58-
type typeA = string | RegExp | (string | RegExp)[];
58+
type typeA = string | RegExp | Array<string | RegExp>;
5959
type typeB = {
6060
/**
6161
* - Prop 1.
@@ -66,19 +66,14 @@ export namespace myTypes {
6666
*/
6767
prop2: string;
6868
};
69-
type typeC = Function | typeB;
69+
type typeC = myTypes.typeB | Function;
70+
const myTypes: {
71+
[x: string]: any;
72+
};
7073
}
71-
/**
72-
* @namespace myTypes
73-
* @global
74-
* @type {Object<string,*>}
75-
*/
76-
export const myTypes: {
77-
[x: string]: any;
78-
};
7974
//// [file2.d.ts]
8075
export namespace testFnTypes {
81-
type input = boolean | Function | myTypes.typeB;
76+
type input = boolean | myTypes.typeC;
8277
}
8378
/** @typedef {boolean|myTypes.typeC} testFnTypes.input */
8479
/**

tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const myTypes: {
6363
[x: string]: any;
6464
};
6565
export namespace myTypes {
66-
type typeA = string | RegExp | (string | RegExp)[];
66+
type typeA = string | RegExp | Array<string | RegExp>;
6767
type typeB = {
6868
/**
6969
* - Prop 1.
@@ -74,7 +74,7 @@ export namespace myTypes {
7474
*/
7575
prop2: string;
7676
};
77-
type typeC = Function | typeB;
77+
type typeC = myTypes.typeB | Function;
7878
}
7979
//// [file2.d.ts]
8080
/** @typedef {boolean|myTypes.typeC} testFnTypes.input */
@@ -94,6 +94,6 @@ export const testFnTypes: {
9494
[x: string]: any;
9595
};
9696
export namespace testFnTypes {
97-
type input = boolean | Function | myTypes.typeB;
97+
type input = boolean | myTypes.typeC;
9898
}
9999
import { myTypes } from "./file.js";
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
tests/cases/conformance/jsdoc/declarations/file.js(8,1): error TS9006: Declaration emit for this file requires using private name 'Base' from module '"tests/cases/conformance/jsdoc/declarations/base"'. An explicit type annotation may unblock declaration emit.
2+
3+
4+
==== tests/cases/conformance/jsdoc/declarations/base.js (0 errors) ====
5+
class Base {
6+
constructor() {}
7+
}
8+
9+
const BaseFactory = () => {
10+
return new Base();
11+
};
12+
13+
BaseFactory.Base = Base;
14+
15+
module.exports = BaseFactory;
16+
17+
==== tests/cases/conformance/jsdoc/declarations/file.js (1 errors) ====
18+
/** @typedef {import('./base')} BaseFactory */
19+
20+
/**
21+
*
22+
* @param {InstanceType<BaseFactory["Base"]>} base
23+
* @returns {InstanceType<BaseFactory["Base"]>}
24+
*/
25+
const test = (base) => {
26+
~~~~~
27+
!!! error TS9006: Declaration emit for this file requires using private name 'Base' from module '"tests/cases/conformance/jsdoc/declarations/base"'. An explicit type annotation may unblock declaration emit.
28+
return base;
29+
};
30+
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsParameterTagReusesInputNodeInEmit1.ts] ////
2+
3+
//// [base.js]
4+
class Base {
5+
constructor() {}
6+
}
7+
8+
const BaseFactory = () => {
9+
return new Base();
10+
};
11+
12+
BaseFactory.Base = Base;
13+
14+
module.exports = BaseFactory;
15+
16+
//// [file.js]
17+
/** @typedef {import('./base')} BaseFactory */
18+
19+
/**
20+
*
21+
* @param {InstanceType<BaseFactory["Base"]>} base
22+
* @returns {InstanceType<BaseFactory["Base"]>}
23+
*/
24+
const test = (base) => {
25+
return base;
26+
};
27+
28+
29+
//// [base.js]
30+
class Base {
31+
constructor() { }
32+
}
33+
const BaseFactory = () => {
34+
return new Base();
35+
};
36+
BaseFactory.Base = Base;
37+
module.exports = BaseFactory;
38+
//// [file.js]
39+
/** @typedef {import('./base')} BaseFactory */
40+
/**
41+
*
42+
* @param {InstanceType<BaseFactory["Base"]>} base
43+
* @returns {InstanceType<BaseFactory["Base"]>}
44+
*/
45+
const test = (base) => {
46+
return base;
47+
};
48+
49+
50+
//// [base.d.ts]
51+
export = BaseFactory;
52+
declare function BaseFactory(): Base;
53+
declare namespace BaseFactory {
54+
export { Base };
55+
}
56+
declare class Base {
57+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
=== tests/cases/conformance/jsdoc/declarations/base.js ===
2+
class Base {
3+
>Base : Symbol(Base, Decl(base.js, 0, 0))
4+
5+
constructor() {}
6+
}
7+
8+
const BaseFactory = () => {
9+
>BaseFactory : Symbol(BaseFactory, Decl(base.js, 4, 5), Decl(base.js, 6, 2))
10+
11+
return new Base();
12+
>Base : Symbol(Base, Decl(base.js, 0, 0))
13+
14+
};
15+
16+
BaseFactory.Base = Base;
17+
>BaseFactory.Base : Symbol(BaseFactory.Base, Decl(base.js, 6, 2))
18+
>BaseFactory : Symbol(BaseFactory, Decl(base.js, 4, 5), Decl(base.js, 6, 2))
19+
>Base : Symbol(BaseFactory.Base, Decl(base.js, 6, 2))
20+
>Base : Symbol(Base, Decl(base.js, 0, 0))
21+
22+
module.exports = BaseFactory;
23+
>module.exports : Symbol("tests/cases/conformance/jsdoc/declarations/base", Decl(base.js, 0, 0))
24+
>module : Symbol(export=, Decl(base.js, 8, 24))
25+
>exports : Symbol(export=, Decl(base.js, 8, 24))
26+
>BaseFactory : Symbol(BaseFactory, Decl(base.js, 4, 5), Decl(base.js, 6, 2))
27+
28+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
29+
/** @typedef {import('./base')} BaseFactory */
30+
31+
/**
32+
*
33+
* @param {InstanceType<BaseFactory["Base"]>} base
34+
* @returns {InstanceType<BaseFactory["Base"]>}
35+
*/
36+
const test = (base) => {
37+
>test : Symbol(test, Decl(file.js, 7, 5))
38+
>base : Symbol(base, Decl(file.js, 7, 14))
39+
40+
return base;
41+
>base : Symbol(base, Decl(file.js, 7, 14))
42+
43+
};
44+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
=== tests/cases/conformance/jsdoc/declarations/base.js ===
2+
class Base {
3+
>Base : Base
4+
5+
constructor() {}
6+
}
7+
8+
const BaseFactory = () => {
9+
>BaseFactory : { (): Base; Base: typeof Base; }
10+
>() => { return new Base();} : { (): Base; Base: typeof Base; }
11+
12+
return new Base();
13+
>new Base() : Base
14+
>Base : typeof Base
15+
16+
};
17+
18+
BaseFactory.Base = Base;
19+
>BaseFactory.Base = Base : typeof Base
20+
>BaseFactory.Base : typeof Base
21+
>BaseFactory : { (): Base; Base: typeof Base; }
22+
>Base : typeof Base
23+
>Base : typeof Base
24+
25+
module.exports = BaseFactory;
26+
>module.exports = BaseFactory : { (): Base; Base: typeof Base; }
27+
>module.exports : { (): Base; Base: typeof Base; }
28+
>module : { "\"tests/cases/conformance/jsdoc/declarations/base\"": { (): Base; Base: typeof Base; }; }
29+
>exports : { (): Base; Base: typeof Base; }
30+
>BaseFactory : { (): Base; Base: typeof Base; }
31+
32+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
33+
/** @typedef {import('./base')} BaseFactory */
34+
35+
/**
36+
*
37+
* @param {InstanceType<BaseFactory["Base"]>} base
38+
* @returns {InstanceType<BaseFactory["Base"]>}
39+
*/
40+
const test = (base) => {
41+
>test : (base: InstanceType<BaseFactory["Base"]>) => Base
42+
>(base) => { return base;} : (base: InstanceType<BaseFactory["Base"]>) => Base
43+
>base : Base
44+
45+
return base;
46+
>base : Base
47+
48+
};
49+
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsParameterTagReusesInputNodeInEmit2.ts] ////
2+
3+
//// [base.js]
4+
class Base {
5+
constructor() {}
6+
}
7+
8+
const BaseFactory = () => {
9+
return new Base();
10+
};
11+
12+
BaseFactory.Base = Base;
13+
14+
module.exports = BaseFactory;
15+
16+
//// [file.js]
17+
/** @typedef {typeof import('./base')} BaseFactory */
18+
19+
/**
20+
*
21+
* @param {InstanceType<BaseFactory["Base"]>} base
22+
* @returns {InstanceType<BaseFactory["Base"]>}
23+
*/
24+
const test = (base) => {
25+
return base;
26+
};
27+
28+
29+
//// [base.js]
30+
class Base {
31+
constructor() { }
32+
}
33+
const BaseFactory = () => {
34+
return new Base();
35+
};
36+
BaseFactory.Base = Base;
37+
module.exports = BaseFactory;
38+
//// [file.js]
39+
/** @typedef {typeof import('./base')} BaseFactory */
40+
/**
41+
*
42+
* @param {InstanceType<BaseFactory["Base"]>} base
43+
* @returns {InstanceType<BaseFactory["Base"]>}
44+
*/
45+
const test = (base) => {
46+
return base;
47+
};
48+
49+
50+
//// [base.d.ts]
51+
export = BaseFactory;
52+
declare function BaseFactory(): Base;
53+
declare namespace BaseFactory {
54+
export { Base };
55+
}
56+
declare class Base {
57+
}
58+
//// [file.d.ts]
59+
/** @typedef {typeof import('./base')} BaseFactory */
60+
/**
61+
*
62+
* @param {InstanceType<BaseFactory["Base"]>} base
63+
* @returns {InstanceType<BaseFactory["Base"]>}
64+
*/
65+
declare function test(base: InstanceType<BaseFactory["Base"]>): InstanceType<BaseFactory["Base"]>;
66+
type BaseFactory = typeof import('./base');
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
=== tests/cases/conformance/jsdoc/declarations/base.js ===
2+
class Base {
3+
>Base : Symbol(Base, Decl(base.js, 0, 0))
4+
5+
constructor() {}
6+
}
7+
8+
const BaseFactory = () => {
9+
>BaseFactory : Symbol(BaseFactory, Decl(base.js, 4, 5), Decl(base.js, 6, 2))
10+
11+
return new Base();
12+
>Base : Symbol(Base, Decl(base.js, 0, 0))
13+
14+
};
15+
16+
BaseFactory.Base = Base;
17+
>BaseFactory.Base : Symbol(BaseFactory.Base, Decl(base.js, 6, 2))
18+
>BaseFactory : Symbol(BaseFactory, Decl(base.js, 4, 5), Decl(base.js, 6, 2))
19+
>Base : Symbol(BaseFactory.Base, Decl(base.js, 6, 2))
20+
>Base : Symbol(Base, Decl(base.js, 0, 0))
21+
22+
module.exports = BaseFactory;
23+
>module.exports : Symbol("tests/cases/conformance/jsdoc/declarations/base", Decl(base.js, 0, 0))
24+
>module : Symbol(export=, Decl(base.js, 8, 24))
25+
>exports : Symbol(export=, Decl(base.js, 8, 24))
26+
>BaseFactory : Symbol(BaseFactory, Decl(base.js, 4, 5), Decl(base.js, 6, 2))
27+
28+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
29+
/** @typedef {typeof import('./base')} BaseFactory */
30+
31+
/**
32+
*
33+
* @param {InstanceType<BaseFactory["Base"]>} base
34+
* @returns {InstanceType<BaseFactory["Base"]>}
35+
*/
36+
const test = (base) => {
37+
>test : Symbol(test, Decl(file.js, 7, 5))
38+
>base : Symbol(base, Decl(file.js, 7, 14))
39+
40+
return base;
41+
>base : Symbol(base, Decl(file.js, 7, 14))
42+
43+
};
44+

0 commit comments

Comments
 (0)