feat(56600): JSDoc @callback doesn't support this parameters via @this (#56610)

This commit is contained in:
Oleksandr T 2023-12-02 01:48:36 +02:00 committed by GitHub
parent 99d243579d
commit 3500c92a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 8 deletions

View File

@ -597,6 +597,7 @@ import {
isJSDocSatisfiesTag,
isJSDocSignature,
isJSDocTemplateTag,
isJSDocThisTag,
isJSDocTypeAlias,
isJSDocTypeAssertion,
isJSDocTypedefTag,
@ -15079,6 +15080,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
let flags = SignatureFlags.None;
let minArgumentCount = 0;
let thisParameter: Symbol | undefined;
let thisTag: JSDocThisTag | undefined = isInJSFile(declaration) ? getJSDocThisTag(declaration) : undefined;
let hasThisParameter = false;
const iife = getImmediatelyInvokedFunctionExpression(declaration);
const isJSConstructSignature = isJSDocConstructSignature(declaration);
@ -15096,6 +15098,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
// signature.
for (let i = isJSConstructSignature ? 1 : 0; i < declaration.parameters.length; i++) {
const param = declaration.parameters[i];
if (isInJSFile(param) && isJSDocThisTag(param)) {
thisTag = param;
continue;
}
let paramSymbol = param.symbol;
const type = isJSDocParameterTag(param) ? (param.typeExpression && param.typeExpression.type) : param.type;
@ -15139,11 +15145,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}
if (isInJSFile(declaration)) {
const thisTag = getJSDocThisTag(declaration);
if (thisTag && thisTag.typeExpression) {
thisParameter = createSymbolWithType(createSymbol(SymbolFlags.FunctionScopedVariable, InternalSymbolName.This), getTypeFromTypeNode(thisTag.typeExpression));
}
if (thisTag && thisTag.typeExpression) {
thisParameter = createSymbolWithType(createSymbol(SymbolFlags.FunctionScopedVariable, InternalSymbolName.This), getTypeFromTypeNode(thisTag.typeExpression));
}
const hostDeclaration = isJSDocSignature(declaration) ? getEffectiveJSDocHost(declaration) : declaration;

View File

@ -9343,7 +9343,7 @@ namespace Parser {
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
const pos = getNodePos();
let child: JSDocPropertyLikeTag | JSDocTypeTag | JSDocTemplateTag | false;
let child: JSDocPropertyLikeTag | JSDocTypeTag | JSDocTemplateTag | JSDocThisTag | false;
let children: JSDocPropertyLikeTag[] | undefined;
while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
@ -9635,7 +9635,7 @@ namespace Parser {
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | JSDocTemplateTag | false;
}
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false {
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | JSDocThisTag | false {
let canParseTag = true;
let seenAsterisk = false;
while (true) {
@ -9672,7 +9672,7 @@ namespace Parser {
}
}
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | false {
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | JSDocTemplateTag | JSDocThisTag | false {
Debug.assert(token() === SyntaxKind.AtToken);
const start = scanner.getTokenFullStart();
nextTokenJSDoc();
@ -9694,6 +9694,8 @@ namespace Parser {
break;
case "template":
return parseTemplateTag(start, tagName, indent, indentText);
case "this":
return parseThisTag(start, tagName, indent, indentText);
default:
return false;
}

View File

@ -0,0 +1,23 @@
//// [tests/cases/conformance/jsdoc/callbackTag4.ts] ////
=== ./a.js ===
/**
* @callback C
* @this {{ a: string, b: number }}
* @param {string} a
* @param {number} b
* @returns {boolean}
*/
/** @type {C} */
const cb = function (a, b) {
>cb : Symbol(cb, Decl(a.js, 9, 5))
>a : Symbol(a, Decl(a.js, 9, 21))
>b : Symbol(b, Decl(a.js, 9, 23))
this
>this : Symbol(this)
return true
}

View File

@ -0,0 +1,25 @@
//// [tests/cases/conformance/jsdoc/callbackTag4.ts] ////
=== ./a.js ===
/**
* @callback C
* @this {{ a: string, b: number }}
* @param {string} a
* @param {number} b
* @returns {boolean}
*/
/** @type {C} */
const cb = function (a, b) {
>cb : C
>function (a, b) { this return true} : (this: { a: string; b: number; }, a: string, b: number) => boolean
>a : string
>b : number
this
>this : { a: string; b: number; }
return true
>true : true
}

View File

@ -0,0 +1,19 @@
// @allowJs: true
// @checkJs: true
// @strict: true
// @noEmit: true
// @filename: ./a.js
/**
* @callback C
* @this {{ a: string, b: number }}
* @param {string} a
* @param {number} b
* @returns {boolean}
*/
/** @type {C} */
const cb = function (a, b) {
this
return true
}