Fix js missing type arguments on existing nodes and jsdoc object literal declaration emit

This commit is contained in:
Wesley Wigham
2020-05-06 12:52:11 -07:00
parent 4f4b44cc20
commit c827007a38
15 changed files with 306 additions and 18 deletions
+21 -2
View File
@@ -5503,6 +5503,10 @@ namespace ts {
return symbol.declarations && find(symbol.declarations, s => !!getEffectiveTypeAnnotationNode(s) && (!enclosingDeclaration || !!findAncestor(s, n => n === enclosingDeclaration)));
}
function getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(existing: TypeNode, type: Type) {
return !(getObjectFlags(type) & ObjectFlags.Reference) || !isTypeReferenceNode(existing) || length(existing.typeArguments) >= getMinTypeArgumentCount((type as TypeReference).target.typeParameters);
}
/**
* Unlike `typeToTypeNodeHelper`, this handles setting up the `AllowUniqueESSymbolType` flag
* so a `unique symbol` is returned when appropriate for the input symbol, rather than `typeof sym`
@@ -5513,7 +5517,7 @@ namespace ts {
if (declWithExistingAnnotation && !isFunctionLikeDeclaration(declWithExistingAnnotation)) {
// try to reuse the existing annotation
const existing = getEffectiveTypeAnnotationNode(declWithExistingAnnotation)!;
if (getTypeFromTypeNode(existing) === type) {
if (getTypeFromTypeNode(existing) === type && getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(existing, type)) {
const result = serializeExistingTypeNode(context, existing, includePrivateSymbol, bundled);
if (result) {
return result;
@@ -5534,7 +5538,7 @@ namespace ts {
function serializeReturnTypeForSignature(context: NodeBuilderContext, type: Type, signature: Signature, includePrivateSymbol?: (s: Symbol) => void, bundled?: boolean) {
if (type !== errorType && context.enclosingDeclaration) {
const annotation = signature.declaration && getEffectiveReturnTypeNode(signature.declaration);
if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && instantiateType(getTypeFromTypeNode(annotation), signature.mapper) === type) {
if (!!findAncestor(annotation, n => n === context.enclosingDeclaration) && annotation && instantiateType(getTypeFromTypeNode(annotation), signature.mapper) === type && getExistingNodeHasNoTypeParametersOrMatchingTypeParameters(annotation, type)) {
const result = serializeExistingTypeNode(context, annotation, includePrivateSymbol, bundled);
if (result) {
return result;
@@ -5575,6 +5579,21 @@ namespace ts {
if (isJSDocVariadicType(node)) {
return createArrayTypeNode(visitNode((node as JSDocVariadicType).type, visitExistingNodeTreeSymbols));
}
if (isJSDocTypeLiteral(node)) {
return createTypeLiteralNode(map(node.jsDocPropertyTags, t => {
const name = isIdentifier(t.name) ? t.name : t.name.right;
const typeViaParent = getTypeOfPropertyOfType(getTypeFromTypeNode(node), name.escapedText);
const overrideTypeNode = typeViaParent && t.typeExpression && getTypeFromTypeNode(t.typeExpression.type) !== typeViaParent ? typeToTypeNodeHelper(typeViaParent, context) : undefined;
return createPropertySignature(
/*modifiers*/ undefined,
name,
t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? createToken(SyntaxKind.QuestionToken) : undefined,
overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) || createKeywordTypeNode(SyntaxKind.AnyKeyword),
/*initializer*/ undefined
);
}));
}
if (isTypeReferenceNode(node) && isIdentifier(node.typeName) && node.typeName.escapedText === "") {
return setOriginalNode(createKeywordTypeNode(SyntaxKind.AnyKeyword), node);
}
@@ -0,0 +1,30 @@
//// [file.js]
/**
* @param {Array} x
*/
function x(x) {}
/**
* @param {Promise} x
*/
function y(x) {}
//// [file.js]
/**
* @param {Array} x
*/
function x(x) { }
/**
* @param {Promise} x
*/
function y(x) { }
//// [file.d.ts]
/**
* @param {Array} x
*/
declare function x(x: any[]): void;
/**
* @param {Promise} x
*/
declare function y(x: Promise<any>): void;
@@ -0,0 +1,15 @@
=== tests/cases/conformance/jsdoc/declarations/file.js ===
/**
* @param {Array} x
*/
function x(x) {}
>x : Symbol(x, Decl(file.js, 0, 0))
>x : Symbol(x, Decl(file.js, 3, 11))
/**
* @param {Promise} x
*/
function y(x) {}
>y : Symbol(y, Decl(file.js, 3, 16))
>x : Symbol(x, Decl(file.js, 7, 11))
@@ -0,0 +1,15 @@
=== tests/cases/conformance/jsdoc/declarations/file.js ===
/**
* @param {Array} x
*/
function x(x) {}
>x : (x: any[]) => void
>x : any[]
/**
* @param {Promise} x
*/
function y(x) {}
>y : (x: Promise<any>) => void
>x : Promise<any>
@@ -0,0 +1,96 @@
//// [file.js]
class X {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {string?} error.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, code}) {}
}
class Y {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {Object} error.suberr
* @param {string?} error.suberr.reason the error reason to send the cancellation with
* @param {string?} error.suberr.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, suberr}) {}
}
//// [file.js]
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
class X {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {string?} error.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
cancel({ reason, code }) {
return __awaiter(this, void 0, void 0, function* () { });
}
}
class Y {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {Object} error.suberr
* @param {string?} error.suberr.reason the error reason to send the cancellation with
* @param {string?} error.suberr.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
cancel({ reason, suberr }) {
return __awaiter(this, void 0, void 0, function* () { });
}
}
//// [file.d.ts]
declare class X {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {string?} error.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
cancel({ reason, code }: {
reason: string | null;
code: string | null;
}): Promise<any>;
}
declare class Y {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {Object} error.suberr
* @param {string?} error.suberr.reason the error reason to send the cancellation with
* @param {string?} error.suberr.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
cancel({ reason, suberr }: {
reason: string | null;
suberr: {
reason: string | null;
code: string | null;
};
}): Promise<any>;
}
@@ -0,0 +1,35 @@
=== tests/cases/conformance/jsdoc/declarations/file.js ===
class X {
>X : Symbol(X, Decl(file.js, 0, 0))
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {string?} error.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, code}) {}
>cancel : Symbol(X.cancel, Decl(file.js, 0, 9))
>reason : Symbol(reason, Decl(file.js, 8, 18))
>code : Symbol(code, Decl(file.js, 8, 25))
}
class Y {
>Y : Symbol(Y, Decl(file.js, 9, 1))
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {Object} error.suberr
* @param {string?} error.suberr.reason the error reason to send the cancellation with
* @param {string?} error.suberr.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, suberr}) {}
>cancel : Symbol(Y.cancel, Decl(file.js, 11, 9))
>reason : Symbol(reason, Decl(file.js, 21, 18))
>suberr : Symbol(suberr, Decl(file.js, 21, 25))
}
@@ -0,0 +1,35 @@
=== tests/cases/conformance/jsdoc/declarations/file.js ===
class X {
>X : X
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {string?} error.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, code}) {}
>cancel : ({ reason, code }: { reason: string | null; code: string | null;}) => Promise<any>
>reason : string
>code : string
}
class Y {
>Y : Y
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {Object} error.suberr
* @param {string?} error.suberr.reason the error reason to send the cancellation with
* @param {string?} error.suberr.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, suberr}) {}
>cancel : ({ reason, suberr }: { reason: string | null; suberr: { reason: string | null; code: string | null; };}) => Promise<any>
>reason : string
>suberr : { reason: string; code: string; }
}
@@ -16,7 +16,7 @@ var numberArray = [5];
* @return {Array}
*/
function returnAnyArray(arr) {
>returnAnyArray : (arr: Array) => Array
>returnAnyArray : (arr: any[]) => any[]
>arr : any[]
return arr;
@@ -46,7 +46,7 @@ var numberPromise = Promise.resolve(5);
* @return {Promise}
*/
function returnAnyPromise(pr) {
>returnAnyPromise : (pr: Promise) => Promise
>returnAnyPromise : (pr: Promise<any>) => Promise<any>
>pr : Promise<any>
return pr;
@@ -16,7 +16,7 @@ var numberArray = [5];
* @return {Array}
*/
function returnNotAnyArray(arr) {
>returnNotAnyArray : (arr: Array) => Array
>returnNotAnyArray : (arr: any[]) => any[]
>arr : any[]
return arr;
@@ -46,7 +46,7 @@ var numberPromise = Promise.resolve(5);
* @return {Promise}
*/
function returnNotAnyPromise(pr) {
>returnNotAnyPromise : (pr: Promise) => Promise
>returnNotAnyPromise : (pr: Promise<any>) => Promise<any>
>pr : Promise<any>
return pr;
@@ -5,6 +5,6 @@ class C {}
/** @param {C} p */
function f(p) {}
>f : (p: C) => void
>f : (p: C<any>) => void
>p : C<any>
@@ -49,7 +49,7 @@ function good4({a, b}) {}
* @param {string} x
*/
function good5({a, b}, x) {}
>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
>good5 : ({ a, b }: { a: string; b: string;}, x: string) => void
>a : string
>b : string
>x : string
@@ -63,7 +63,7 @@ function good5({a, b}, x) {}
* @param {string} OBJECTION.d - meh
*/
function good6({a, b}, {c, d}) {}
>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
>good6 : ({ a, b }: { a: string; b: string;}, { c, d }: { c: string; d: string;}) => void
>a : string
>b : string
>c : string
@@ -77,7 +77,7 @@ function good6({a, b}, {c, d}) {}
* @param {string} y
*/
function good7(x, {a, b}, y) {}
>good7 : (x: number, { a, b }: * @param {string} obj.a * @param {string} obj.b, y: string) => void
>good7 : (x: number, { a, b }: { a: string; b: string;}, y: string) => void
>x : number
>a : string
>b : string
@@ -89,7 +89,7 @@ function good7(x, {a, b}, y) {}
* @param {string} obj.b
*/
function good8({a, b}) {}
>good8 : ({ a, b }: * @param {string} obj.a * @param {string} obj.b) => void
>good8 : ({ a, b }: { a: string; b: string;}) => void
>a : string
>b : string
@@ -23,7 +23,7 @@ normal(12);
* @param {string} [opts1.w="hi"] doc5
*/
function foo1(opts1) {
>foo1 : (opts1: * @param {string} opts1.x doc2 * @param {string=} opts1.y doc3 * @param {string} [opts1.z] doc4 * @param {string} [opts1.w] doc5) => void
>foo1 : (opts1: { x: string; y?: string | undefined; z: string; w: string;}) => void
>opts1 : { x: string; y?: string | undefined; z?: string; w?: string; }
opts1.x;
@@ -45,7 +45,7 @@ foo1({x: 'abc'});
* @param {string=} opts2[].anotherY
*/
function foo2(/** @param opts2 bad idea theatre! */opts2) {
>foo2 : (opts2: * @param {string} opts2.anotherX * @param {string=} opts2.anotherY) => void
>foo2 : (opts2: { anotherX: string; anotherY?: string | undefined;}) => void
>opts2 : { anotherX: string; anotherY?: string | undefined; }[]
opts2[0].anotherX;
@@ -69,7 +69,7 @@ foo2([{anotherX: "world"}]);
* @param {string} opts3.x
*/
function foo3(opts3) {
>foo3 : (opts3: * @param {string} opts3.x) => void
>foo3 : (opts3: { x: string;}) => void
>opts3 : { x: string; }
opts3.x;
@@ -92,7 +92,7 @@ foo3({x: 'abc'});
* @param {string} [opts4[].w="hi"]
*/
function foo4(opts4) {
>foo4 : (opts4: * @param {string} opts4.x * @param {string=} opts4.y * @param {string} [opts4.z] * @param {string} [opts4.w]) => void
>foo4 : (opts4: { x: string; y?: string | undefined; z: string; w: string;}) => void
>opts4 : { x: string; y?: string | undefined; z?: string; w?: string; }[]
opts4[0].x;
@@ -122,7 +122,7 @@ foo4([{ x: 'hi' }]);
* @param {number} opts5[].unnest - Here we are almost all the way back at the beginning.
*/
function foo5(opts5) {
>foo5 : (opts5: * @param {string} opts5.help - (This one is just normal) * @param { * @param {string} opts5.what.a - (Another normal one) * @param { * @param {string} opts5.what.bad.idea - I don't think you can get back out of this level... * @param {boolean} opts5.what.bad.oh - Oh ... that's how you do it.} opts5.what.bad - Now we're nesting inside a nested type} opts5.what - Look at us go! Here's the first nest! * @param {number} opts5.unnest - Here we are almost all the way back at the beginning.) => void
>foo5 : (opts5: { help: string; what: { a: string; bad: { idea: string; oh: boolean; }; }; unnest: number;}) => void
>opts5 : { help: string; what: { a: string; bad: { idea: string; oh: boolean; }[]; }; unnest: number; }[]
opts5[0].what.bad[0].idea;
@@ -26,13 +26,13 @@ function Zet(t) {
* @param {T} o.nested
*/
Zet.prototype.add = function(v, o) {
>Zet.prototype.add = function(v, o) { this.u = v || o.nested return this.u} : (v: T, o: * @param {T} o.nested) => T
>Zet.prototype.add = function(v, o) { this.u = v || o.nested return this.u} : (v: T, o: { nested: T; }) => T
>Zet.prototype.add : any
>Zet.prototype : any
>Zet : typeof Zet
>prototype : any
>add : any
>function(v, o) { this.u = v || o.nested return this.u} : (v: T, o: * @param {T} o.nested) => T
>function(v, o) { this.u = v || o.nested return this.u} : (v: T, o: { nested: T; }) => T
>v : T
>o : { nested: T; }
@@ -0,0 +1,14 @@
// @allowJs: true
// @checkJs: true
// @target: es5
// @outDir: ./out
// @declaration: true
// @filename: file.js
/**
* @param {Array} x
*/
function x(x) {}
/**
* @param {Promise} x
*/
function y(x) {}
@@ -0,0 +1,29 @@
// @allowJs: true
// @checkJs: true
// @target: es6
// @outDir: ./out
// @declaration: true
// @filename: file.js
class X {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {string?} error.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, code}) {}
}
class Y {
/**
* Cancels the request, sending a cancellation to the other party
* @param {Object} error __auto_generated__
* @param {string?} error.reason the error reason to send the cancellation with
* @param {Object} error.suberr
* @param {string?} error.suberr.reason the error reason to send the cancellation with
* @param {string?} error.suberr.code the error code to send the cancellation with
* @returns {Promise.<*>} resolves when the event has been sent.
*/
async cancel({reason, suberr}) {}
}