diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 35b28e0452011..464c31134d0f0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6699,7 +6699,11 @@ namespace ts { let hasThisParameter: boolean; const iife = getImmediatelyInvokedFunctionExpression(declaration); const isJSConstructSignature = isJSDocConstructSignature(declaration); - const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration); + const isUntypedSignatureInJSFile = !iife && + isInJavaScriptFile(declaration) && + isValueSignatureDeclaration(declaration) && + !hasJSDocParameterTags(declaration) && + !getJSDocType(declaration); // If this is a JSDoc construct signature, then skip the first parameter in the // parameter list. The first parameter represents the return type of the construct @@ -9123,7 +9127,8 @@ namespace ts { } function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { - return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && isContextSensitiveFunctionLikeDeclaration(func); + return (isInJavaScriptFile(func) && isFunctionDeclaration(func) || isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && + isContextSensitiveFunctionLikeDeclaration(func); } function getTypeWithoutSignatures(type: Type): Type { @@ -14191,49 +14196,49 @@ namespace ts { // Return contextual type of parameter or undefined if no contextual type is available function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined { const func = parameter.parent; - if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) { - const iife = getImmediatelyInvokedFunctionExpression(func); - if (iife && iife.arguments) { - const indexOfParameter = func.parameters.indexOf(parameter); - if (parameter.dotDotDotToken) { - const restTypes: Type[] = []; - for (let i = indexOfParameter; i < iife.arguments.length; i++) { - restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i]))); - } - return restTypes.length ? createArrayType(getUnionType(restTypes)) : undefined; - } - const links = getNodeLinks(iife); - const cached = links.resolvedSignature; - links.resolvedSignature = anySignature; - const type = indexOfParameter < iife.arguments.length ? - getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter])) : - parameter.initializer ? undefined : undefinedWideningType; - links.resolvedSignature = cached; - return type; + if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) { + return undefined; + } + const iife = getImmediatelyInvokedFunctionExpression(func); + if (iife && iife.arguments) { + const indexOfParameter = func.parameters.indexOf(parameter); + if (parameter.dotDotDotToken) { + const restTypes: Type[] = []; + for (let i = indexOfParameter; i < iife.arguments.length; i++) { + restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i]))); + } + return restTypes.length ? createArrayType(getUnionType(restTypes)) : undefined; + } + const links = getNodeLinks(iife); + const cached = links.resolvedSignature; + links.resolvedSignature = anySignature; + const type = indexOfParameter < iife.arguments.length ? + getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter])) : + parameter.initializer ? undefined : undefinedWideningType; + links.resolvedSignature = cached; + return type; + } + const contextualSignature = getContextualSignature(func); + if (contextualSignature) { + const funcHasRestParameters = hasRestParameter(func); + const len = func.parameters.length - (funcHasRestParameters ? 1 : 0); + let indexOfParameter = func.parameters.indexOf(parameter); + if (getThisParameter(func) !== undefined && !contextualSignature.thisParameter) { + Debug.assert(indexOfParameter !== 0); // Otherwise we should not have called `getContextuallyTypedParameterType`. + indexOfParameter -= 1; } - const contextualSignature = getContextualSignature(func); - if (contextualSignature) { - const funcHasRestParameters = hasRestParameter(func); - const len = func.parameters.length - (funcHasRestParameters ? 1 : 0); - let indexOfParameter = func.parameters.indexOf(parameter); - if (getThisParameter(func) !== undefined && !contextualSignature.thisParameter) { - Debug.assert(indexOfParameter !== 0); // Otherwise we should not have called `getContextuallyTypedParameterType`. - indexOfParameter -= 1; - } - if (indexOfParameter < len) { - return getTypeAtPosition(contextualSignature, indexOfParameter); - } + if (indexOfParameter < len) { + return getTypeAtPosition(contextualSignature, indexOfParameter); + } - // If last parameter is contextually rest parameter get its type - if (funcHasRestParameters && - indexOfParameter === (func.parameters.length - 1) && - isRestParameterIndex(contextualSignature, func.parameters.length - 1)) { - return getTypeOfSymbol(lastOrUndefined(contextualSignature.parameters)); - } + // If last parameter is contextually rest parameter get its type + if (funcHasRestParameters && + indexOfParameter === (func.parameters.length - 1) && + isRestParameterIndex(contextualSignature, func.parameters.length - 1)) { + return getTypeOfSymbol(lastOrUndefined(contextualSignature.parameters)); } } - return undefined; } // In a variable, parameter or property declaration with a type annotation, @@ -14796,7 +14801,16 @@ namespace ts { // union type of return types from these signatures function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature { Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); - const type = getContextualTypeForFunctionLikeDeclaration(node); + let type: Type; + if (isInJavaScriptFile(node)) { + const jsdoc = getJSDocType(node); + if (jsdoc) { + type = getTypeFromTypeNode(jsdoc); + } + } + if (!type) { + type = getContextualTypeForFunctionLikeDeclaration(node); + } if (!type) { return undefined; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 235b10e4cf19d..a5ba7c30cd2d3 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1958,6 +1958,18 @@ namespace ts { return false; } + export type ValueSignatureDeclaration = + | FunctionDeclaration + | MethodDeclaration + | ConstructorDeclaration + | AccessorDeclaration + | FunctionExpression + | ArrowFunction; + + export function isValueSignatureDeclaration(node: Node): node is ValueSignatureDeclaration { + return isFunctionExpression(node) || isArrowFunction(node) || isMethodOrAccessor(node) || isFunctionDeclaration(node) || isConstructorDeclaration(node); + } + function walkUp(node: Node, kind: SyntaxKind) { while (node && node.kind === kind) { node = node.parent; diff --git a/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty1.types b/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty1.types index 41cf9fff7393a..2601309b504b2 100644 --- a/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty1.types +++ b/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty1.types @@ -20,12 +20,12 @@ const obj = { /** @type {function(number): number} */ method1(n1) { ->method1 : (n1: any) => any ->n1 : any +>method1 : (n1: number) => number +>n1 : number return n1 + 42; ->n1 + 42 : any ->n1 : any +>n1 + 42 : number +>n1 : number >42 : 42 }, @@ -44,10 +44,10 @@ const obj = { /** @type {function(number): number} */ arrowFunc: (num) => num + 42 >arrowFunc : (arg0: number) => number ->(num) => num + 42 : (num: any) => any ->num : any ->num + 42 : any ->num : any +>(num) => num + 42 : (num: number) => number +>num : number +>num + 42 : number +>num : number >42 : 42 } obj.foo = 'string' diff --git a/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.errors.txt b/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.errors.txt index 33c83e6117236..48559d79cb189 100644 --- a/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.errors.txt +++ b/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.errors.txt @@ -1,11 +1,9 @@ tests/cases/conformance/jsdoc/0.js(5,3): error TS2322: Type 'number' is not assignable to type 'string | undefined'. -tests/cases/conformance/jsdoc/0.js(7,3): error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'. +tests/cases/conformance/jsdoc/0.js(7,3): error TS2322: Type '(n1: number) => string' is not assignable to type '(arg0: number) => number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/jsdoc/0.js(11,3): error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'. +tests/cases/conformance/jsdoc/0.js(11,3): error TS2322: Type '(n1: number) => string' is not assignable to type '(arg0: number) => number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/jsdoc/0.js(13,3): error TS2322: Type '(num?: string) => string' is not assignable to type '(arg0: number) => number'. - Types of parameters 'num' and 'arg0' are incompatible. - Type 'number' is not assignable to type 'string | undefined'. +tests/cases/conformance/jsdoc/0.js(13,15): error TS2322: Type '"0"' is not assignable to type 'number'. tests/cases/conformance/jsdoc/0.js(15,3): error TS2322: Type 'undefined' is not assignable to type 'string'. tests/cases/conformance/jsdoc/0.js(19,5): error TS2322: Type 'number' is not assignable to type 'string'. tests/cases/conformance/jsdoc/0.js(22,22): error TS2345: Argument of type '"0"' is not assignable to parameter of type 'number'. @@ -22,21 +20,19 @@ tests/cases/conformance/jsdoc/0.js(22,22): error TS2345: Argument of type '"0"' /** @type {function(number): number} */ method1(n1) { ~~~~~~~ -!!! error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'. +!!! error TS2322: Type '(n1: number) => string' is not assignable to type '(arg0: number) => number'. !!! error TS2322: Type 'string' is not assignable to type 'number'. return "42"; }, /** @type {function(number): number} */ method2: (n1) => "lol", ~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '(n1: any) => string' is not assignable to type '(arg0: number) => number'. +!!! error TS2322: Type '(n1: number) => string' is not assignable to type '(arg0: number) => number'. !!! error TS2322: Type 'string' is not assignable to type 'number'. /** @type {function(number): number} */ arrowFunc: (num="0") => num + 42, - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -!!! error TS2322: Type '(num?: string) => string' is not assignable to type '(arg0: number) => number'. -!!! error TS2322: Types of parameters 'num' and 'arg0' are incompatible. -!!! error TS2322: Type 'number' is not assignable to type 'string | undefined'. + ~~~~~~~ +!!! error TS2322: Type '"0"' is not assignable to type 'number'. /** @type {string} */ lol ~~~ diff --git a/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.types b/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.types index 443826c7aeb58..c7f2b7bbeb007 100644 --- a/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.types +++ b/tests/baselines/reference/checkJsdocTypeTagOnObjectProperty2.types @@ -14,8 +14,8 @@ const obj = { /** @type {function(number): number} */ method1(n1) { ->method1 : (n1: any) => string ->n1 : any +>method1 : (n1: number) => string +>n1 : number return "42"; >"42" : "42" @@ -24,18 +24,18 @@ const obj = { /** @type {function(number): number} */ method2: (n1) => "lol", >method2 : (arg0: number) => number ->(n1) => "lol" : (n1: any) => string ->n1 : any +>(n1) => "lol" : (n1: number) => string +>n1 : number >"lol" : "lol" /** @type {function(number): number} */ arrowFunc: (num="0") => num + 42, >arrowFunc : (arg0: number) => number ->(num="0") => num + 42 : (num?: string) => string ->num : string +>(num="0") => num + 42 : (num?: number) => number +>num : number >"0" : "0" ->num + 42 : string ->num : string +>num + 42 : number +>num : number >42 : 42 /** @type {string} */ diff --git a/tests/baselines/reference/jsdocTypeTag.js b/tests/baselines/reference/jsdocTypeTag.js index 4789b1d26afce..394fb5a53da01 100644 --- a/tests/baselines/reference/jsdocTypeTag.js +++ b/tests/baselines/reference/jsdocTypeTag.js @@ -60,6 +60,12 @@ var obj; /** @type {Function} */ var Func; + +/** @type {(s: string) => number} */ +var f; + +/** @type {new (s: string) => { s: string }} */ +var ctor; //// [b.ts] var S: string; @@ -82,6 +88,8 @@ var nullable: number | null; var Obj: any; var obj: any; var Func: Function; +var f: (s: string) => number; +var ctor: new (s: string) => { s: string }; //// [a.js] @@ -125,6 +133,10 @@ var Obj; var obj; /** @type {Function} */ var Func; +/** @type {(s: string) => number} */ +var f; +/** @type {new (s: string) => { s: string }} */ +var ctor; //// [b.js] var S; var s; @@ -146,3 +158,5 @@ var nullable; var Obj; var obj; var Func; +var f; +var ctor; diff --git a/tests/baselines/reference/jsdocTypeTag.symbols b/tests/baselines/reference/jsdocTypeTag.symbols index 77df5b119f470..db299c10d2b16 100644 --- a/tests/baselines/reference/jsdocTypeTag.symbols +++ b/tests/baselines/reference/jsdocTypeTag.symbols @@ -79,6 +79,14 @@ var obj; var Func; >Func : Symbol(Func, Decl(a.js, 58, 3), Decl(b.ts, 19, 3)) +/** @type {(s: string) => number} */ +var f; +>f : Symbol(f, Decl(a.js, 61, 3), Decl(b.ts, 20, 3)) + +/** @type {new (s: string) => { s: string }} */ +var ctor; +>ctor : Symbol(ctor, Decl(a.js, 64, 3), Decl(b.ts, 21, 3)) + === tests/cases/conformance/jsdoc/b.ts === var S: string; >S : Symbol(S, Decl(a.js, 1, 3), Decl(b.ts, 0, 3)) @@ -143,3 +151,12 @@ var Func: Function; >Func : Symbol(Func, Decl(a.js, 58, 3), Decl(b.ts, 19, 3)) >Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +var f: (s: string) => number; +>f : Symbol(f, Decl(a.js, 61, 3), Decl(b.ts, 20, 3)) +>s : Symbol(s, Decl(b.ts, 20, 8)) + +var ctor: new (s: string) => { s: string }; +>ctor : Symbol(ctor, Decl(a.js, 64, 3), Decl(b.ts, 21, 3)) +>s : Symbol(s, Decl(b.ts, 21, 15)) +>s : Symbol(s, Decl(b.ts, 21, 30)) + diff --git a/tests/baselines/reference/jsdocTypeTag.types b/tests/baselines/reference/jsdocTypeTag.types index 9813a186a00d9..754a4b725cdc0 100644 --- a/tests/baselines/reference/jsdocTypeTag.types +++ b/tests/baselines/reference/jsdocTypeTag.types @@ -79,6 +79,14 @@ var obj; var Func; >Func : Function +/** @type {(s: string) => number} */ +var f; +>f : (s: string) => number + +/** @type {new (s: string) => { s: string }} */ +var ctor; +>ctor : new (s: string) => { s: string; } + === tests/cases/conformance/jsdoc/b.ts === var S: string; >S : string @@ -146,3 +154,12 @@ var Func: Function; >Func : Function >Function : Function +var f: (s: string) => number; +>f : (s: string) => number +>s : string + +var ctor: new (s: string) => { s: string }; +>ctor : new (s: string) => { s: string; } +>s : string +>s : string + diff --git a/tests/baselines/reference/jsdocTypeTagParameterType.errors.txt b/tests/baselines/reference/jsdocTypeTagParameterType.errors.txt new file mode 100644 index 0000000000000..d03e8211a18ff --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagParameterType.errors.txt @@ -0,0 +1,18 @@ +tests/cases/conformance/jsdoc/a.js(3,5): error TS2322: Type '1' is not assignable to type 'string'. +tests/cases/conformance/jsdoc/a.js(7,5): error TS2322: Type '1' is not assignable to type 'string'. + + +==== tests/cases/conformance/jsdoc/a.js (2 errors) ==== + /** @type {function(string): void} */ + const f = (value) => { + value = 1 // should error + ~~~~~ +!!! error TS2322: Type '1' is not assignable to type 'string'. + }; + /** @type {(s: string) => void} */ + function g(s) { + s = 1 // Should error + ~ +!!! error TS2322: Type '1' is not assignable to type 'string'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTypeTagParameterType.symbols b/tests/baselines/reference/jsdocTypeTagParameterType.symbols new file mode 100644 index 0000000000000..e9d098bda4b64 --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagParameterType.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/jsdoc/a.js === +/** @type {function(string): void} */ +const f = (value) => { +>f : Symbol(f, Decl(a.js, 1, 5)) +>value : Symbol(value, Decl(a.js, 1, 11)) + + value = 1 // should error +>value : Symbol(value, Decl(a.js, 1, 11)) + +}; +/** @type {(s: string) => void} */ +function g(s) { +>g : Symbol(g, Decl(a.js, 3, 2)) +>s : Symbol(s, Decl(a.js, 5, 11)) + + s = 1 // Should error +>s : Symbol(s, Decl(a.js, 5, 11)) +} + diff --git a/tests/baselines/reference/jsdocTypeTagParameterType.types b/tests/baselines/reference/jsdocTypeTagParameterType.types new file mode 100644 index 0000000000000..e750b6c6be6d0 --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagParameterType.types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/jsdoc/a.js === +/** @type {function(string): void} */ +const f = (value) => { +>f : (arg0: string) => void +>(value) => { value = 1 // should error} : (value: string) => void +>value : string + + value = 1 // should error +>value = 1 : 1 +>value : string +>1 : 1 + +}; +/** @type {(s: string) => void} */ +function g(s) { +>g : (s: string) => void +>s : string + + s = 1 // Should error +>s = 1 : 1 +>s : string +>1 : 1 +} + diff --git a/tests/baselines/reference/jsdocTypeTagRequiredParameters.errors.txt b/tests/baselines/reference/jsdocTypeTagRequiredParameters.errors.txt new file mode 100644 index 0000000000000..4afde4e5037db --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagRequiredParameters.errors.txt @@ -0,0 +1,26 @@ +tests/cases/conformance/jsdoc/a.js(11,1): error TS2554: Expected 1 arguments, but got 0. +tests/cases/conformance/jsdoc/a.js(12,1): error TS2554: Expected 1 arguments, but got 0. +tests/cases/conformance/jsdoc/a.js(13,1): error TS2554: Expected 1 arguments, but got 0. + + +==== tests/cases/conformance/jsdoc/a.js (3 errors) ==== + /** @type {function(string): void} */ + const f = (value) => { + }; + /** @type {(s: string) => void} */ + function g(s) { + } + /** @type {{(s: string): void}} */ + function h(s) { + } + + f() // should error + ~~~ +!!! error TS2554: Expected 1 arguments, but got 0. + g() // should error + ~~~ +!!! error TS2554: Expected 1 arguments, but got 0. + h() + ~~~ +!!! error TS2554: Expected 1 arguments, but got 0. + \ No newline at end of file diff --git a/tests/baselines/reference/jsdocTypeTagRequiredParameters.symbols b/tests/baselines/reference/jsdocTypeTagRequiredParameters.symbols new file mode 100644 index 0000000000000..1c740c4f49190 --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagRequiredParameters.symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/jsdoc/a.js === +/** @type {function(string): void} */ +const f = (value) => { +>f : Symbol(f, Decl(a.js, 1, 5)) +>value : Symbol(value, Decl(a.js, 1, 11)) + +}; +/** @type {(s: string) => void} */ +function g(s) { +>g : Symbol(g, Decl(a.js, 2, 2)) +>s : Symbol(s, Decl(a.js, 4, 11)) +} +/** @type {{(s: string): void}} */ +function h(s) { +>h : Symbol(h, Decl(a.js, 5, 1)) +>s : Symbol(s, Decl(a.js, 7, 11)) +} + +f() // should error +>f : Symbol(f, Decl(a.js, 1, 5)) + +g() // should error +>g : Symbol(g, Decl(a.js, 2, 2)) + +h() +>h : Symbol(h, Decl(a.js, 5, 1)) + diff --git a/tests/baselines/reference/jsdocTypeTagRequiredParameters.types b/tests/baselines/reference/jsdocTypeTagRequiredParameters.types new file mode 100644 index 0000000000000..daca778b07185 --- /dev/null +++ b/tests/baselines/reference/jsdocTypeTagRequiredParameters.types @@ -0,0 +1,31 @@ +=== tests/cases/conformance/jsdoc/a.js === +/** @type {function(string): void} */ +const f = (value) => { +>f : (arg0: string) => void +>(value) => {} : (value: string) => void +>value : string + +}; +/** @type {(s: string) => void} */ +function g(s) { +>g : (s: string) => void +>s : string +} +/** @type {{(s: string): void}} */ +function h(s) { +>h : (s: string) => void +>s : string +} + +f() // should error +>f() : void +>f : (arg0: string) => void + +g() // should error +>g() : void +>g : (s: string) => void + +h() +>h() : void +>h : (s: string) => void + diff --git a/tests/cases/conformance/jsdoc/jsdocTypeTag.ts b/tests/cases/conformance/jsdoc/jsdocTypeTag.ts index 1c19771a3cd38..b5fdd397fa765 100644 --- a/tests/cases/conformance/jsdoc/jsdocTypeTag.ts +++ b/tests/cases/conformance/jsdoc/jsdocTypeTag.ts @@ -63,6 +63,12 @@ var obj; /** @type {Function} */ var Func; +/** @type {(s: string) => number} */ +var f; + +/** @type {new (s: string) => { s: string }} */ +var ctor; + // @filename: b.ts var S: string; var s: string; @@ -84,3 +90,5 @@ var nullable: number | null; var Obj: any; var obj: any; var Func: Function; +var f: (s: string) => number; +var ctor: new (s: string) => { s: string }; diff --git a/tests/cases/conformance/jsdoc/jsdocTypeTagParameterType.ts b/tests/cases/conformance/jsdoc/jsdocTypeTagParameterType.ts new file mode 100644 index 0000000000000..598555d1bb38b --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTypeTagParameterType.ts @@ -0,0 +1,15 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @strict: true +// @noImplicitAny: true +// @Filename: a.js + +/** @type {function(string): void} */ +const f = (value) => { + value = 1 // should error +}; +/** @type {(s: string) => void} */ +function g(s) { + s = 1 // Should error +} diff --git a/tests/cases/conformance/jsdoc/jsdocTypeTagRequiredParameters.ts b/tests/cases/conformance/jsdoc/jsdocTypeTagRequiredParameters.ts new file mode 100644 index 0000000000000..6991b3e83867f --- /dev/null +++ b/tests/cases/conformance/jsdoc/jsdocTypeTagRequiredParameters.ts @@ -0,0 +1,20 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @strict: true +// @noImplicitAny: true +// @Filename: a.js + +/** @type {function(string): void} */ +const f = (value) => { +}; +/** @type {(s: string) => void} */ +function g(s) { +} +/** @type {{(s: string): void}} */ +function h(s) { +} + +f() // should error +g() // should error +h() diff --git a/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts b/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts index ab57b32aaacc2..49d7133d9c460 100644 --- a/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts +++ b/tests/cases/fourslash/annotateWithTypeFromJSDoc16.ts @@ -5,6 +5,7 @@ verify.codeFix({ description: "Annotate with type from JSDoc", + index: 0, newFileContent: `/** @type {function(*, ...number, ...boolean): void} */ var x: (arg0: any, arg1: number[], ...rest: boolean[]) => void = (x, ys, ...zs) => { };`,