mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-12 01:48:33 -05:00
Stricter test that JSDoc @type tag matches function signature (#25615)
This commit is contained in:
@@ -4682,13 +4682,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
// Use contextual parameter type if one is available
|
||||
let type: Type | undefined;
|
||||
if (declaration.symbol.escapedName === "this") {
|
||||
type = getContextualThisParameterType(func);
|
||||
}
|
||||
else {
|
||||
type = getContextuallyTypedParameterType(declaration);
|
||||
}
|
||||
const type = declaration.symbol.escapedName === "this" ? getContextualThisParameterType(func) : getContextuallyTypedParameterType(declaration);
|
||||
if (type) {
|
||||
return addOptionality(type, isOptional);
|
||||
}
|
||||
@@ -16209,7 +16203,7 @@ namespace ts {
|
||||
|
||||
// If the given type is an object or union type with a single signature, and if that signature has at
|
||||
// least as many parameters as the given function, return the signature. Otherwise return undefined.
|
||||
function getContextualCallSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature | undefined {
|
||||
function getContextualCallSignature(type: Type, node: SignatureDeclaration): Signature | undefined {
|
||||
const signatures = getSignaturesOfType(type, SignatureKind.Call);
|
||||
if (signatures.length === 1) {
|
||||
const signature = signatures[0];
|
||||
@@ -16220,7 +16214,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** If the contextual signature has fewer parameters than the function expression, do not use it */
|
||||
function isAritySmaller(signature: Signature, target: FunctionExpression | ArrowFunction | MethodDeclaration) {
|
||||
function isAritySmaller(signature: Signature, target: SignatureDeclaration) {
|
||||
let targetParameterCount = 0;
|
||||
for (; targetParameterCount < target.parameters.length; targetParameterCount++) {
|
||||
const param = target.parameters[targetParameterCount];
|
||||
@@ -23538,12 +23532,13 @@ namespace ts {
|
||||
// yielded values. The only way to trigger these errors is to try checking its return type.
|
||||
getReturnTypeOfSignature(getSignatureFromDeclaration(node));
|
||||
}
|
||||
// A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const typeTag = getJSDocTypeTag(node);
|
||||
if (typeTag && typeTag.typeExpression && !getSignaturesOfType(getTypeFromTypeNode(typeTag.typeExpression), SignatureKind.Call).length) {
|
||||
error(typeTag, Diagnostics.The_type_of_a_function_declaration_must_be_callable);
|
||||
}
|
||||
}
|
||||
|
||||
// A js function declaration can have a @type tag instead of a return type node, but that type must have a call signature
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const typeTag = getJSDocTypeTag(node);
|
||||
if (typeTag && typeTag.typeExpression && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node)) {
|
||||
error(typeTag, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4021,7 +4021,7 @@
|
||||
"category": "Error",
|
||||
"code": 8029
|
||||
},
|
||||
"The type of a function declaration must be callable.": {
|
||||
"The type of a function declaration must match the function's signature.": {
|
||||
"category": "Error",
|
||||
"code": 8030
|
||||
},
|
||||
|
||||
@@ -4,11 +4,12 @@ tests/cases/conformance/jsdoc/test.js(7,24): error TS2322: Type 'number' is not
|
||||
tests/cases/conformance/jsdoc/test.js(10,17): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/test.js(12,14): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/test.js(14,24): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/test.js(28,5): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(34,5): error TS2322: Type '1 | 2' is not assignable to type '2 | 3'.
|
||||
Type '1' is not assignable to type '2 | 3'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/test.js (7 errors) ====
|
||||
==== tests/cases/conformance/jsdoc/test.js (8 errors) ====
|
||||
// all 6 should error on return statement/expression
|
||||
/** @type {(x: number) => string} */
|
||||
function h(x) { return x }
|
||||
@@ -49,6 +50,8 @@ tests/cases/conformance/jsdoc/test.js(34,5): error TS2322: Type '1 | 2' is not a
|
||||
/** @typedef {{(s: string): 0 | 1; (b: boolean): 2 | 3 }} Gioconda */
|
||||
|
||||
/** @type {Gioconda} */
|
||||
~~~~~~~~~~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
function monaLisa(sb) {
|
||||
return typeof sb === 'string' ? 1 : 2;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
tests/cases/conformance/jsdoc/test.js(1,5): error TS8030: The type of a function declaration must be callable.
|
||||
tests/cases/conformance/jsdoc/test.js(1,5): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(7,5): error TS2322: Type '(prop: any) => void' is not assignable to type '{ prop: string; }'.
|
||||
Property 'prop' is missing in type '(prop: any) => void'.
|
||||
tests/cases/conformance/jsdoc/test.js(10,5): error TS8030: The type of a function declaration must match the function's signature.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/test.js (2 errors) ====
|
||||
==== tests/cases/conformance/jsdoc/test.js (3 errors) ====
|
||||
/** @type {number} */
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must be callable.
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
function f() {
|
||||
return 1
|
||||
}
|
||||
@@ -17,4 +18,16 @@ tests/cases/conformance/jsdoc/test.js(7,5): error TS2322: Type '(prop: any) => v
|
||||
!!! error TS2322: Type '(prop: any) => void' is not assignable to type '{ prop: string; }'.
|
||||
!!! error TS2322: Property 'prop' is missing in type '(prop: any) => void'.
|
||||
}
|
||||
|
||||
/** @type {(a: number) => number} */
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
function add1(a, b) { return a + b; }
|
||||
|
||||
/** @type {(a: number, b: number) => number} */
|
||||
function add2(a, b) { return a + b; }
|
||||
|
||||
// TODO: Should be an error since signature doesn't match.
|
||||
/** @type {(a: number, b: number, c: number) => number} */
|
||||
function add3(a, b) { return a + b; }
|
||||
|
||||
@@ -12,3 +12,28 @@ var g = function (prop) {
|
||||
>prop : Symbol(prop, Decl(test.js, 6, 18))
|
||||
}
|
||||
|
||||
/** @type {(a: number) => number} */
|
||||
function add1(a, b) { return a + b; }
|
||||
>add1 : Symbol(add1, Decl(test.js, 7, 1))
|
||||
>a : Symbol(a, Decl(test.js, 10, 14))
|
||||
>b : Symbol(b, Decl(test.js, 10, 16))
|
||||
>a : Symbol(a, Decl(test.js, 10, 14))
|
||||
>b : Symbol(b, Decl(test.js, 10, 16))
|
||||
|
||||
/** @type {(a: number, b: number) => number} */
|
||||
function add2(a, b) { return a + b; }
|
||||
>add2 : Symbol(add2, Decl(test.js, 10, 37))
|
||||
>a : Symbol(a, Decl(test.js, 13, 14))
|
||||
>b : Symbol(b, Decl(test.js, 13, 16))
|
||||
>a : Symbol(a, Decl(test.js, 13, 14))
|
||||
>b : Symbol(b, Decl(test.js, 13, 16))
|
||||
|
||||
// TODO: Should be an error since signature doesn't match.
|
||||
/** @type {(a: number, b: number, c: number) => number} */
|
||||
function add3(a, b) { return a + b; }
|
||||
>add3 : Symbol(add3, Decl(test.js, 13, 37))
|
||||
>a : Symbol(a, Decl(test.js, 17, 14))
|
||||
>b : Symbol(b, Decl(test.js, 17, 16))
|
||||
>a : Symbol(a, Decl(test.js, 17, 14))
|
||||
>b : Symbol(b, Decl(test.js, 17, 16))
|
||||
|
||||
|
||||
@@ -14,3 +14,31 @@ var g = function (prop) {
|
||||
>prop : any
|
||||
}
|
||||
|
||||
/** @type {(a: number) => number} */
|
||||
function add1(a, b) { return a + b; }
|
||||
>add1 : (a: any, b: any) => number
|
||||
>a : any
|
||||
>b : any
|
||||
>a + b : any
|
||||
>a : any
|
||||
>b : any
|
||||
|
||||
/** @type {(a: number, b: number) => number} */
|
||||
function add2(a, b) { return a + b; }
|
||||
>add2 : (a: number, b: number) => number
|
||||
>a : number
|
||||
>b : number
|
||||
>a + b : number
|
||||
>a : number
|
||||
>b : number
|
||||
|
||||
// TODO: Should be an error since signature doesn't match.
|
||||
/** @type {(a: number, b: number, c: number) => number} */
|
||||
function add3(a, b) { return a + b; }
|
||||
>add3 : (a: number, b: number) => number
|
||||
>a : number
|
||||
>b : number
|
||||
>a + b : number
|
||||
>a : number
|
||||
>b : number
|
||||
|
||||
|
||||
@@ -11,3 +11,13 @@ function f() {
|
||||
/** @type {{ prop: string }} */
|
||||
var g = function (prop) {
|
||||
}
|
||||
|
||||
/** @type {(a: number) => number} */
|
||||
function add1(a, b) { return a + b; }
|
||||
|
||||
/** @type {(a: number, b: number) => number} */
|
||||
function add2(a, b) { return a + b; }
|
||||
|
||||
// TODO: Should be an error since signature doesn't match.
|
||||
/** @type {(a: number, b: number, c: number) => number} */
|
||||
function add3(a, b) { return a + b; }
|
||||
|
||||
Reference in New Issue
Block a user