Skip to content

Commit

Permalink
Fix js missing type arguments on existing nodes and jsdoc object lite…
Browse files Browse the repository at this point in the history
…ral declaration emit
  • Loading branch information
weswigham committed May 6, 2020
1 parent 4f4b44c commit c827007
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 18 deletions.
23 changes: 21 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down
30 changes: 30 additions & 0 deletions tests/baselines/reference/jsDeclarationsMissingGenerics.js
Original file line number Diff line number Diff line change
@@ -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;
15 changes: 15 additions & 0 deletions tests/baselines/reference/jsDeclarationsMissingGenerics.symbols
Original file line number Diff line number Diff line change
@@ -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))

15 changes: 15 additions & 0 deletions tests/baselines/reference/jsDeclarationsMissingGenerics.types
Original file line number Diff line number Diff line change
@@ -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>

96 changes: 96 additions & 0 deletions tests/baselines/reference/jsDeclarationsNestedParams.js
Original file line number Diff line number Diff line change
@@ -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>;
}
35 changes: 35 additions & 0 deletions tests/baselines/reference/jsDeclarationsNestedParams.symbols
Original file line number Diff line number Diff line change
@@ -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))
}

35 changes: 35 additions & 0 deletions tests/baselines/reference/jsDeclarationsNestedParams.types
Original file line number Diff line number Diff line change
@@ -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; }
}

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var numberArray = [5];
* @return {Array}
*/
function returnAnyArray(arr) {
>returnAnyArray : (arr: Array) => Array
>returnAnyArray : (arr: any[]) => any[]
>arr : any[]

return arr;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var numberArray = [5];
* @return {Array}
*/
function returnNotAnyArray(arr) {
>returnNotAnyArray : (arr: Array) => Array
>returnNotAnyArray : (arr: any[]) => any[]
>arr : any[]

return arr;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ class C {}

/** @param {C} p */
function f(p) {}
>f : (p: C) => void
>f : (p: C<any>) => void
>p : C<any>

8 changes: 4 additions & 4 deletions tests/baselines/reference/jsdocParamTag2.types
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand Down

0 comments on commit c827007

Please sign in to comment.