From 8b8af5fd7d3dee21a0a38f75c7d13d53ae7345cd Mon Sep 17 00:00:00 2001 From: Oleksandr T Date: Tue, 26 Sep 2023 22:00:31 +0300 Subject: [PATCH] fix(55796): forbid this tag for arrow functions --- src/compiler/checker.ts | 11 ++++++++ tests/baselines/reference/thisTag3.errors.txt | 21 +++++++++++++++ tests/baselines/reference/thisTag3.symbols | 21 +++++++++++++++ tests/baselines/reference/thisTag3.types | 27 +++++++++++++++++++ tests/cases/conformance/jsdoc/thisTag3.ts | 16 +++++++++++ 5 files changed, 96 insertions(+) create mode 100644 tests/baselines/reference/thisTag3.errors.txt create mode 100644 tests/baselines/reference/thisTag3.symbols create mode 100644 tests/baselines/reference/thisTag3.types create mode 100644 tests/cases/conformance/jsdoc/thisTag3.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 1748e660e9259..1bb754b696522 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -775,6 +775,7 @@ import { JSDocSatisfiesTag, JSDocSignature, JSDocTemplateTag, + JSDocThisTag, JSDocTypeAssertion, JSDocTypedefTag, JSDocTypeExpression, @@ -40989,6 +40990,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkJSDocParameterTag(node: JSDocParameterTag) { checkSourceElement(node.typeExpression); } + function checkJSDocPropertyTag(node: JSDocPropertyTag) { checkSourceElement(node.typeExpression); } @@ -41004,6 +41006,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function checkJSDocThisTag(node: JSDocThisTag) { + const host = getEffectiveJSDocHost(node); + if (host && isArrowFunction(host)) { + error(node.tagName, Diagnostics.An_arrow_function_cannot_have_a_this_parameter); + } + } + function checkJSDocImplementsTag(node: JSDocImplementsTag): void { const classLike = getEffectiveJSDocHost(node); if (!classLike || !isClassDeclaration(classLike) && !isClassExpression(classLike)) { @@ -45724,6 +45733,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return checkJSDocAccessibilityModifiers(node as JSDocPublicTag | JSDocProtectedTag | JSDocPrivateTag); case SyntaxKind.JSDocSatisfiesTag: return checkJSDocSatisfiesTag(node as JSDocSatisfiesTag); + case SyntaxKind.JSDocThisTag: + return checkJSDocThisTag(node as JSDocThisTag); case SyntaxKind.IndexedAccessType: return checkIndexedAccessType(node as IndexedAccessTypeNode); case SyntaxKind.MappedType: diff --git a/tests/baselines/reference/thisTag3.errors.txt b/tests/baselines/reference/thisTag3.errors.txt new file mode 100644 index 0000000000000..81623b16cefa9 --- /dev/null +++ b/tests/baselines/reference/thisTag3.errors.txt @@ -0,0 +1,21 @@ +/a.js(7,9): error TS2730: An arrow function cannot have a 'this' parameter. +/a.js(10,21): error TS2339: Property 'fn' does not exist on type 'C'. + + +==== /a.js (2 errors) ==== + /** + * @typedef {{fn(a: string): void}} T + */ + + class C { + /** + * @this {T} + ~~~~ +!!! error TS2730: An arrow function cannot have a 'this' parameter. + * @param {string} a + */ + p = (a) => this.fn("" + a); + ~~ +!!! error TS2339: Property 'fn' does not exist on type 'C'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/thisTag3.symbols b/tests/baselines/reference/thisTag3.symbols new file mode 100644 index 0000000000000..9fbc0b5aabf53 --- /dev/null +++ b/tests/baselines/reference/thisTag3.symbols @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/jsdoc/thisTag3.ts] //// + +=== /a.js === +/** + * @typedef {{fn(a: string): void}} T + */ + +class C { +>C : Symbol(C, Decl(a.js, 0, 0)) + + /** + * @this {T} + * @param {string} a + */ + p = (a) => this.fn("" + a); +>p : Symbol(C.p, Decl(a.js, 4, 9)) +>a : Symbol(a, Decl(a.js, 9, 9)) +>this : Symbol(C, Decl(a.js, 0, 0)) +>a : Symbol(a, Decl(a.js, 9, 9)) +} + diff --git a/tests/baselines/reference/thisTag3.types b/tests/baselines/reference/thisTag3.types new file mode 100644 index 0000000000000..08334eacaef0f --- /dev/null +++ b/tests/baselines/reference/thisTag3.types @@ -0,0 +1,27 @@ +//// [tests/cases/conformance/jsdoc/thisTag3.ts] //// + +=== /a.js === +/** + * @typedef {{fn(a: string): void}} T + */ + +class C { +>C : C + + /** + * @this {T} + * @param {string} a + */ + p = (a) => this.fn("" + a); +>p : (this: T, a: string) => any +>(a) => this.fn("" + a) : (this: T, a: string) => any +>a : string +>this.fn("" + a) : any +>this.fn : any +>this : this +>fn : any +>"" + a : string +>"" : "" +>a : string +} + diff --git a/tests/cases/conformance/jsdoc/thisTag3.ts b/tests/cases/conformance/jsdoc/thisTag3.ts new file mode 100644 index 0000000000000..1db6d34b21c95 --- /dev/null +++ b/tests/cases/conformance/jsdoc/thisTag3.ts @@ -0,0 +1,16 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @filename: /a.js + +/** + * @typedef {{fn(a: string): void}} T + */ + +class C { + /** + * @this {T} + * @param {string} a + */ + p = (a) => this.fn("" + a); +}