It was my first job. The web was alive and well at this point but still very much in it's infancy. Newspapers had only recently moved on from calling it "the information superhighway". No-one was doing real programming for the web - the desktop was where it was at.
As for me, I was writing call centre software. It was all very exciting. Here was the idea: the phone on your desk would start ringing and through the magic of TAPI our app would be presented with the telephone number of the dialer. It would then look up that telephone number in the appropriate CRM application and pop the callers details on the screen. You'd pick up the phone and bellow "why hello Mr Jones!" and either impress the caller with your incredible fore-knowledge of who had rung you or perhaps terrify them with our Brave New Orwellian World.
My job was to work out how to call into the APIs of the various CRM applications / databases being used and extract the relevant information. So it goes without saying that I have spent a lot of time with badly documented APIs. Or in fact undocumented APIs. I know pain my friend...
Hours and days were spent debugging and walking APIs just to find out what they could do and what information they exposed. This, I need hardly say, was dull and tedious work. Having spent longer than I care to remember with no more information on an API than method names has left its mark on me. I am consequently keener than your average dev on documentation and intellisense. When you've stared at the coalface of the Lotus Notes API for 2 weeks with only Dephi 3 as your constant companion you'd feel the same way too. (This was before the days of Google and actually being able to find stuff on the internet.)
If you can convey information about the API that you're building then I'd say you're duty-bound to do so. Or at least that it's good manners.
When I started getting involved with the Definitely Typed project my focus was on giving good Intellisense. Where there was documentation for an API I wanted to get that popping in front of users when they hit the "." key:
With 0.8.2, the TypeScript compiler and tools now support JSDoc comments.
In the TypeScript implementation, because types are already part of the system, we allow the JSDoc type annotation to be elided, as in the example above.
You can now document a variety of language constructs (including classes, modules, interfaces, and functions) with comments that become part of the information displayed to the user. We’ve also started extending lib.d.ts, the default JS and DOM API library, with JSDoc comments.
Partly as an exercise in getting better acquainted with TypeScript and partly responding to my instinctive need to have nicely documented APIs I decided to start adding JSDoc comments to the world's most popular typings file
Well a number of reasons:
- I used
jquery.d.tsalready myself and I'm a firm believer in eating your own dogfood
- jQuery is well documented. I needed a source of information to power my JSDoc and api.jquery.com had my back.
jquery.d.tswas widely used. Given how ubiquitous jQuery has become this typing file was unsurprisingly the most popular in the world. That was key for me as I wanted feedback - if I was making a mess of the typings I wanted someone to pitch in and tell me.
Just to digress once more, points #2 and #3 turned out to be of particular note.
Concerning point #2, I did find the occasional error or inconsistency in the jQuery API documentation. These were definitely the exception rather than the rule though. And thanks to the very helpful Dave Methvin these actually lead to minor improvements to the jQuery API documentation.
Concerning point #3 I did indeed get feedback. As well as enriching
jquery.d.ts with JSDoc goodness I also found myself fixing slight errors in the typings. Here and there I would find examples where
jquery.d.ts was out of line the with API documentation. Where this was the case I would amend the typings to bring them into line - trying to make
jquery.d.ts entirely API-compliant. This was not always popular. But despite the heat it generated I think it ended up leading to a better typing file. I'm again grateful for Dave Methvin's thoughtful contributions.
I wanted to take an example of API documentation and demonstrate how that can be applied to a typing file with particular focus on how JSDoc comments can be created to drive Intellisense. So let's take everyone's favourite jQuery method:
val. The documentation of
val can be found here: api.jquery.com/val
By the way, check out the *entirely* intuitive URL. Now you've clocked just how straightforward that is you've probably a fair idea how you could find pretty much any jQuery documentation you might need without recourse to Google. Brilliant!
And now let's look at
Many changes yes? Let's break it down a little.
The first thing to note is the
number setter method:
Let's have a look at the jQuery documentation for the simple setter:
valueA string of text or an array of strings corresponding to the value of each matched element to set as selected/checked.
See the problem? There is *no*
number setter. The typings are wrong. So let's remedy this:
Array of String setters#
The documentation states that we have setters which accept
Array of String. These are already modeled in the existing typings by the
So let's enrich these typings with some JSDoc:
If you look you can see we've added a related JSDoc style comment block prior to each overload. The first part of the comment ("Set the value of...") is the overarching Intellisense that is displayed. Each of the
@param statements represents each of the parameters and it's associated comment. By comparing the API documentation to the JSDoc it's pretty clear how the API has been transformed into useful JSDoc.
It's worth noting that I could have taken the choice to customise the
@param value comments based on the overload I was JSDoc-ing. Arguably it would have been more useful to have something like this instead:
After some pondering I decided not to take this approach, just to maintain that close relationship between
jquery.d.ts and api.jquery.com. It's open to debate how useful that relationship actually is so I thought I'd just highlight this as a choice I made.
The jQuery documentation for the getter looks like this:
Description: Get the current value of the first element in the set of matched elements.
val() overload can return a
number or a
string. Unfortunately there is no real way to model that in TypeScript at present due to the absence of "union types". Union types are being discussed at present but in TypeScript v1.0 world the only viable approach is returning the
any type. This implies
Function and straight on 'til morning. So clearly this isn't accurate but importantly it also allows for the possibility of
The final getter typing with JSDoc applied ends up looking like this:
As you can see the "Get the current value..." from the API docs has been used as the overarching Intellisense that is displayed for the getter.
Finally we're going to take a look at the
Function setter which is documented as follows:
.val( function(index, value) )](http://api.jquery.com/val/#val-functionindex--value)function(index, value)Type: Function()A function returning the value to set.
thisis the current element. Receives the index position of the element in the set and the old value as arguments.
If you cast your eyes back to the original typings for the
Function setter you'll see they look like this:
This is a good start but it's less accurate than it could be in a number of ways:
number- we needn't keep it as an
valueis the old value - we know from our getter that this can be a
string. So we can lose the
anyin favour of overloads which specify different types for
- The return value of the function is the value that should be set. We know from our other setters that the possible types allowed here are
string. (And yes I'm as puzzled as you are that the getter can return a
numberbut the setter can't set one.) That being the case it makes sense for us to have overloads with functions that return both
So, we've got a little tidy up to do for #1 and extra overloads to add for #2 and #3. We're going to replace the single
Function setter with 3 overloads to cater for #2. Then for #3 we're going to take each of the 3 overloads we've just created and make 2 overloads place of each to handle the different return types. This will lead us with the grand total of 6 overloads to model our
A cursory glance shows that each of the overloads above shares the same JSDoc. Each has the "Set the value..." from the API docs as the overarching Intellisense that is displayed for the
Function setter. And each has the same
@param func comment as well.
This post is much longer than I ever intended it to be. But I wanted to show how easy it is to create typings with JSDoc to drive Intellisense. For no obvious reason people generally don't make a great deal of use of JSDoc when creating typings. Perhaps the creators have no good source of documentation (a common problem). Or perhaps people are not even aware it's a possibility - they don't know about the TypeScript support of JSDoc. In case it's the latter I think this post was worth writing.