Skip to content

Commit c827007

Browse files
committed
Fix js missing type arguments on existing nodes and jsdoc object literal declaration emit
1 parent 4f4b44c commit c827007

15 files changed

+306
-18
lines changed

src/compiler/checker.ts

+21-2
Original file line numberDiff line numberDiff line change
@@ -5503,6 +5503,10 @@ namespace ts {
55035503
return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration)));
55045504
}
55055505

5506+
function getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(existing: TypeNode, type: Type) {
5507+
return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) || length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters);
5508+
}
5509+
55065510
/**
55075511
* Unlike `typeToTypeNodeHelper`, this handles setting up the `AllowUniqueESSymbolType` flag
55085512
* so a `unique symbol` is returned when appropriate for the input symbol, rather than `typeof sym`
@@ -5513,7 +5517,7 @@ namespace ts {
55135517
if (declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation)) {
55145518
// try to reuse the existing annotation
55155519
const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation)!;
5516-
if (getTypeFromTypeNode(existing) === type) {
5520+
if (getTypeFromTypeNode(existing) === type && getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(existing, type)) {
55175521
const result = serializeExistingTypeNode(context, existing, includePrivateSymbol, bundled);
55185522
if (result) {
55195523
return result;
@@ -5534,7 +5538,7 @@ namespace ts {
55345538
function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) {
55355539
if (type !== errorType && context.enclosingDeclaration) {
55365540
const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration);
5537-
if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && instantiateType(getTypeFromTypeNode(annotation), signature.mapper) === type) {
5541+
if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && instantiateType(getTypeFromTypeNode(annotation), signature.mapper) === type && getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(annotation, type)) {
55385542
const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled);
55395543
if (result) {
55405544
return result;
@@ -5575,6 +5579,21 @@ namespace ts {
55755579
if (isJSDocVariadicType(node)) {
55765580
return createArrayTypeNode(visitNode((node as JSDocVariadicType).type, visitExistingNodeTreeSymbols));
55775581
}
5582+
if (isJSDocTypeLiteral(node)) {
5583+
return createTypeLiteralNode(map(node.jsDocPropertyTags, t => {
5584+
const name = isIdentifier(t.name) ? t.name : t.name.right;
5585+
const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(node), name.escapedText);
5586+
const overrideTypeNode = typeViaParent && t.typeExpression && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined;
5587+
5588+
return createPropertySignature(
5589+
/*modifiers*/ undefined,
5590+
name,
5591+
t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? createToken(SyntaxKind.QuestionToken) : undefined,
5592+
overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) || createKeywordTypeNode(SyntaxKind.AnyKeyword),
5593+
/*initializer*/ undefined
5594+
);
5595+
}));
5596+
}
55785597
if (isTypeReferenceNode(node) && isIdentifier(node.typeName) && node.typeName.escapedText === "") {
55795598
return setOriginalNode(createKeywordTypeNode(SyntaxKind.AnyKeyword), node);
55805599
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//// [file.js]
2+
/**
3+
* @param {Array} x
4+
*/
5+
function x(x) {}
6+
/**
7+
* @param {Promise} x
8+
*/
9+
function y(x) {}
10+
11+
//// [file.js]
12+
/**
13+
* @param {Array} x
14+
*/
15+
function x(x) { }
16+
/**
17+
* @param {Promise} x
18+
*/
19+
function y(x) { }
20+
21+
22+
//// [file.d.ts]
23+
/**
24+
* @param {Array} x
25+
*/
26+
declare function x(x: any[]): void;
27+
/**
28+
* @param {Promise} x
29+
*/
30+
declare function y(x: Promise<any>): void;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
2+
/**
3+
* @param {Array} x
4+
*/
5+
function x(x) {}
6+
>x : Symbol(x, Decl(file.js, 0, 0))
7+
>x : Symbol(x, Decl(file.js, 3, 11))
8+
9+
/**
10+
* @param {Promise} x
11+
*/
12+
function y(x) {}
13+
>y : Symbol(y, Decl(file.js, 3, 16))
14+
>x : Symbol(x, Decl(file.js, 7, 11))
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
2+
/**
3+
* @param {Array} x
4+
*/
5+
function x(x) {}
6+
>x : (x: any[]) => void
7+
>x : any[]
8+
9+
/**
10+
* @param {Promise} x
11+
*/
12+
function y(x) {}
13+
>y : (x: Promise<any>) => void
14+
>x : Promise<any>
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//// [file.js]
2+
class X {
3+
/**
4+
* Cancels the request, sending a cancellation to the other party
5+
* @param {Object} error __auto_generated__
6+
* @param {string?} error.reason the error reason to send the cancellation with
7+
* @param {string?} error.code the error code to send the cancellation with
8+
* @returns {Promise.<*>} resolves when the event has been sent.
9+
*/
10+
async cancel({reason, code}) {}
11+
}
12+
13+
class Y {
14+
/**
15+
* Cancels the request, sending a cancellation to the other party
16+
* @param {Object} error __auto_generated__
17+
* @param {string?} error.reason the error reason to send the cancellation with
18+
* @param {Object} error.suberr
19+
* @param {string?} error.suberr.reason the error reason to send the cancellation with
20+
* @param {string?} error.suberr.code the error code to send the cancellation with
21+
* @returns {Promise.<*>} resolves when the event has been sent.
22+
*/
23+
async cancel({reason, suberr}) {}
24+
}
25+
26+
27+
//// [file.js]
28+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
29+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
30+
return new (P || (P = Promise))(function (resolve, reject) {
31+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
33+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
34+
step((generator = generator.apply(thisArg, _arguments || [])).next());
35+
});
36+
};
37+
class X {
38+
/**
39+
* Cancels the request, sending a cancellation to the other party
40+
* @param {Object} error __auto_generated__
41+
* @param {string?} error.reason the error reason to send the cancellation with
42+
* @param {string?} error.code the error code to send the cancellation with
43+
* @returns {Promise.<*>} resolves when the event has been sent.
44+
*/
45+
cancel({ reason, code }) {
46+
return __awaiter(this, void 0, void 0, function* () { });
47+
}
48+
}
49+
class Y {
50+
/**
51+
* Cancels the request, sending a cancellation to the other party
52+
* @param {Object} error __auto_generated__
53+
* @param {string?} error.reason the error reason to send the cancellation with
54+
* @param {Object} error.suberr
55+
* @param {string?} error.suberr.reason the error reason to send the cancellation with
56+
* @param {string?} error.suberr.code the error code to send the cancellation with
57+
* @returns {Promise.<*>} resolves when the event has been sent.
58+
*/
59+
cancel({ reason, suberr }) {
60+
return __awaiter(this, void 0, void 0, function* () { });
61+
}
62+
}
63+
64+
65+
//// [file.d.ts]
66+
declare class X {
67+
/**
68+
* Cancels the request, sending a cancellation to the other party
69+
* @param {Object} error __auto_generated__
70+
* @param {string?} error.reason the error reason to send the cancellation with
71+
* @param {string?} error.code the error code to send the cancellation with
72+
* @returns {Promise.<*>} resolves when the event has been sent.
73+
*/
74+
cancel({ reason, code }: {
75+
reason: string | null;
76+
code: string | null;
77+
}): Promise<any>;
78+
}
79+
declare class Y {
80+
/**
81+
* Cancels the request, sending a cancellation to the other party
82+
* @param {Object} error __auto_generated__
83+
* @param {string?} error.reason the error reason to send the cancellation with
84+
* @param {Object} error.suberr
85+
* @param {string?} error.suberr.reason the error reason to send the cancellation with
86+
* @param {string?} error.suberr.code the error code to send the cancellation with
87+
* @returns {Promise.<*>} resolves when the event has been sent.
88+
*/
89+
cancel({ reason, suberr }: {
90+
reason: string | null;
91+
suberr: {
92+
reason: string | null;
93+
code: string | null;
94+
};
95+
}): Promise<any>;
96+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
2+
class X {
3+
>X : Symbol(X, Decl(file.js, 0, 0))
4+
5+
/**
6+
* Cancels the request, sending a cancellation to the other party
7+
* @param {Object} error __auto_generated__
8+
* @param {string?} error.reason the error reason to send the cancellation with
9+
* @param {string?} error.code the error code to send the cancellation with
10+
* @returns {Promise.<*>} resolves when the event has been sent.
11+
*/
12+
async cancel({reason, code}) {}
13+
>cancel : Symbol(X.cancel, Decl(file.js, 0, 9))
14+
>reason : Symbol(reason, Decl(file.js, 8, 18))
15+
>code : Symbol(code, Decl(file.js, 8, 25))
16+
}
17+
18+
class Y {
19+
>Y : Symbol(Y, Decl(file.js, 9, 1))
20+
21+
/**
22+
* Cancels the request, sending a cancellation to the other party
23+
* @param {Object} error __auto_generated__
24+
* @param {string?} error.reason the error reason to send the cancellation with
25+
* @param {Object} error.suberr
26+
* @param {string?} error.suberr.reason the error reason to send the cancellation with
27+
* @param {string?} error.suberr.code the error code to send the cancellation with
28+
* @returns {Promise.<*>} resolves when the event has been sent.
29+
*/
30+
async cancel({reason, suberr}) {}
31+
>cancel : Symbol(Y.cancel, Decl(file.js, 11, 9))
32+
>reason : Symbol(reason, Decl(file.js, 21, 18))
33+
>suberr : Symbol(suberr, Decl(file.js, 21, 25))
34+
}
35+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
2+
class X {
3+
>X : X
4+
5+
/**
6+
* Cancels the request, sending a cancellation to the other party
7+
* @param {Object} error __auto_generated__
8+
* @param {string?} error.reason the error reason to send the cancellation with
9+
* @param {string?} error.code the error code to send the cancellation with
10+
* @returns {Promise.<*>} resolves when the event has been sent.
11+
*/
12+
async cancel({reason, code}) {}
13+
>cancel : ({ reason, code }: { reason: string | null; code: string | null;}) => Promise<any>
14+
>reason : string
15+
>code : string
16+
}
17+
18+
class Y {
19+
>Y : Y
20+
21+
/**
22+
* Cancels the request, sending a cancellation to the other party
23+
* @param {Object} error __auto_generated__
24+
* @param {string?} error.reason the error reason to send the cancellation with
25+
* @param {Object} error.suberr
26+
* @param {string?} error.suberr.reason the error reason to send the cancellation with
27+
* @param {string?} error.suberr.code the error code to send the cancellation with
28+
* @returns {Promise.<*>} resolves when the event has been sent.
29+
*/
30+
async cancel({reason, suberr}) {}
31+
>cancel : ({ reason, suberr }: { reason: string | null; suberr: { reason: string | null; code: string | null; };}) => Promise<any>
32+
>reason : string
33+
>suberr : { reason: string; code: string; }
34+
}
35+

tests/baselines/reference/jsdocArrayObjectPromiseImplicitAny.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var numberArray = [5];
1616
* @return {Array}
1717
*/
1818
function returnAnyArray(arr) {
19-
>returnAnyArray : (arr: Array) => Array
19+
>returnAnyArray : (arr: any[]) => any[]
2020
>arr : any[]
2121

2222
return arr;
@@ -46,7 +46,7 @@ var numberPromise = Promise.resolve(5);
4646
* @return {Promise}
4747
*/
4848
function returnAnyPromise(pr) {
49-
>returnAnyPromise : (pr: Promise) => Promise
49+
>returnAnyPromise : (pr: Promise<any>) => Promise<any>
5050
>pr : Promise<any>
5151

5252
return pr;

tests/baselines/reference/jsdocArrayObjectPromiseNoImplicitAny.types

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var numberArray = [5];
1616
* @return {Array}
1717
*/
1818
function returnNotAnyArray(arr) {
19-
>returnNotAnyArray : (arr: Array) => Array
19+
>returnNotAnyArray : (arr: any[]) => any[]
2020
>arr : any[]
2121

2222
return arr;
@@ -46,7 +46,7 @@ var numberPromise = Promise.resolve(5);
4646
* @return {Promise}
4747
*/
4848
function returnNotAnyPromise(pr) {
49-
>returnNotAnyPromise : (pr: Promise) => Promise
49+
>returnNotAnyPromise : (pr: Promise<any>) => Promise<any>
5050
>pr : Promise<any>
5151

5252
return pr;

tests/baselines/reference/jsdocClassMissingTypeArguments.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ class C {}
55

66
/** @param {C} p */
77
function f(p) {}
8-
>f : (p: C) => void
8+
>f : (p: C<any>) => void
99
>p : C<any>
1010

tests/baselines/reference/jsdocParamTag2.types

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function good4({a, b}) {}
4949
* @param {string} x
5050
*/
5151
function good5({a, b}, x) {}
52-
>good5 : ({ a, b }: * @param {string} obj.a - this is like the saddest way to specify a type * @param {string} obj.b - but it sure does allow a lot of documentation, x: string) => void
52+
>good5 : ({ a, b }: { a: string; b: string;}, x: string) => void
5353
>a : string
5454
>b : string
5555
>x : string
@@ -63,7 +63,7 @@ function good5({a, b}, x) {}
6363
* @param {string} OBJECTION.d - meh
6464
*/
6565
function good6({a, b}, {c, d}) {}
66-
>good6 : ({ a, b }: * @param {string} obj.a * @param {string} obj.b - but it sure does allow a lot of documentation, { c, d }: * @param {string} OBJECTION.c * @param {string} OBJECTION.d - meh) => void
66+
>good6 : ({ a, b }: { a: string; b: string;}, { c, d }: { c: string; d: string;}) => void
6767
>a : string
6868
>b : string
6969
>c : string
@@ -77,7 +77,7 @@ function good6({a, b}, {c, d}) {}
7777
* @param {string} y
7878
*/
7979
function good7(x, {a, b}, y) {}
80-
>good7 : (x: number, { a, b }: * @param {string} obj.a * @param {string} obj.b, y: string) => void
80+
>good7 : (x: number, { a, b }: { a: string; b: string;}, y: string) => void
8181
>x : number
8282
>a : string
8383
>b : string
@@ -89,7 +89,7 @@ function good7(x, {a, b}, y) {}
8989
* @param {string} obj.b
9090
*/
9191
function good8({a, b}) {}
92-
>good8 : ({ a, b }: * @param {string} obj.a * @param {string} obj.b) => void
92+
>good8 : ({ a, b }: { a: string; b: string;}) => void
9393
>a : string
9494
>b : string
9595

0 commit comments

Comments
 (0)