Update (2023)
I actually did a talk on how to get tsc + JSDoc that answers this question and a few more:
And created a package to help with the tsconfig boilerplate:
- https://npmjs.org/jswt
npx jswt init
Original Question
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?
@typedef {(other: Person) => string} PersonGreetinstead of just defining it as "Function"@callbackinstead of@typedef {Function}. I've filed a bug with tsc: github.com/microsoft/TypeScript/issues/50274Personshould be a class with a .create` function that has accurate docs on it, using a normalnew Person(name)instead of a faux static Person.create? No need for all those separate "unconnected" pieces of JSDoc that way. (Even if you also add astatic createto the class, yielding a new Person instance).