I’m trying to use tsc
with plain, Vanilla JS and I’m stumped on how to declare the type a function.
It seems like it should be this simple:
/** @type PersonGreet */ person.greet = function greet(other) { return `Hello ${other.name}, my name is ${person.name}!`; };
Edit: /** @type PersonGreet */
is correct. The current behavior is a bug in tsc
. The selected answer below gives valid workarounds.
Reduced Test Case
Ignore the fact that someone may want to refactor this into using classes or prototypes or some such – it serves well as a demonstration of the problem.
Repo: https://github.com/BeyondCodeBootcamp/hello-tsc
"use strict"; /** * @typedef {Object} Person * @property {String} name * @property {PersonGreet} greet */ /** * @typedef {Function} PersonGreet * @param {Person} other * @returns {String} */ let Person = {}; /** * Creates a person * @param {Object} p * @param {String} p.name * @returns {Person} */ Person.create = function (p) { let person = {}; person.name = p.name; ///////////////////////////////////////////////////////////////////////////////// // // error TS7006: Parameter 'other' implicitly has an 'any' type. <======= WRONG! // ///////////////////////////////////////////////////////////////////////////////// /** @type PersonGreet */ person.greet = function greet(other) { return `Hello ${other.name}, my name is ${person.name}!`; }; return person; }; module.exports = Person;
Incorrectly Typed as “any”
When I run tsc
to check it gives an error about an implicit any:
tsc -p jsconfig.json
person.js:28:33 - error TS7006: Parameter 'other' implicitly has an 'any' type. 28 person.greet = function greet(other) { ~~~~~ Found 1 error in person.js:28
What to do?
To me this seems like a bug in tsc
… but this is JS 101 stuff, surely there must be a way to type a function?
What annotation do I need to use to declare the function’s type? Or can tsc
/ tsserver
/ typescript
just not handle this kind of rudimentary use of JS?
Advertisement
Answer
Solution 1
You should use @callback
instead of @function
like so:
"use strict"; /** * @typedef {Object} Person * @property {String} name * @property {PersonGreet} greet */ /** * @callback PersonGreet * @param {Person} other * @returns {String} */ let Person = {}; /** * Creates a person * @param {Object} p * @param {String} p.name * @returns {Person} */ Person.create = function (p) { let person = {}; person.name = p.name; /** @type {PersonGreet} */ person.greet = function greet(other) { return `Hello ${other.name}, my name is ${person.name}!`; }; return person; }; module.exports = Person;
Solution 2
Or, declare a @typedef
using typescript syntax like the following:
/** * @typedef {(other: Person) => string} PersonGreet */