Typescript: Improve documentation on creating definition files for JavaScript libraries.

Created on 6 Apr 2017  ·  8Comments  ·  Source: microsoft/TypeScript

This is neither a bug nor a language feature suggestion, so I'm not sure if this is the right place.

I have been using TypeScript off and on for the past couple years. While the set of available type definitions has grown greatly over time, in almost every project I run into at least one library that requires me to write my own .d.ts. Every time I approach this problem I usually find myself spending half a day trying to figure out the correct syntax to get a 10-20 line .d.ts file working correctly. Each time I start with the TypeScript documentation, escalate to Google, and usually find myself reading through a dozen closed issues in the TypeScript GitHub repo, many of which are using syntax and techniques that are out of date.

I recognize that JavaScript is all over the place itself with regards to how libraries are authored (global, UMD, commonjs, AMD, ES6, TypeScript, etc.) and I find https://www.typescriptlang.org/docs/handbook/declaration-files/library-structures.html to be a great starting point for figuring out what kind of library I have. Unfortunately, once I figure out the type of library I have (Modular Library in my latest case) I feel like the docs kind of drop you without much guidance on where to go next.

If I click through to the next section of the handbook "By Example" I don't see anything talking about what to do with my "Modular Library" (in fact, Modular is nowhere on the page). There seems to be quite a bit about Globals there, but not much else. The same goes for the Deep Dive section, which has a ton of information but really no guide on how to create a definition file for my Modular Library. The problem here is that all I know at this point is that I have a "Modular Library" thanks to the "Library Structures" page. I don't know what of the gobs of information being presented to me is relevant for my use case.

If I keep clicking through to Templates I do see a few things named "module" something or other (that is kind of close to Modular), but they just show me the definition file, not the JavaScript file that the definition is for so I once again find myself unsure of which of the things I want. In my _current_ case I have a JavaScript file that has module.exports = { foo: constructorFunction, bar: constructorFunction } and that doesn't seem to quite line up with any of the examples (though it is hard to say since the examples don't include any JavaScript).

Since there are so many different ways to setup JavaScript libraries, I think there would be value in having a small repository that has a bunch of different example JavaScript files with the type definitions sitting next to them (or perhaps in the same file for ease of comparison). I could try to browse through DefinitelyTyped, but there appear to be thousands of libraries in there and trying to find one that is "kind of similar to what I have" would take ages.

As far as the documentation itself goes, I think there would be great value in having a clear path forward for the reader once they have identified their library type. Right now it seems like the documentation for all of the different library types is jumbled together but in most cases a user is probably coming to the documentation with one library type they need to deal with, and seeing _only_ documentation for that library type would greatly simplify the documentation I suspect.

Docs

Most helpful comment

No, because they are all missing the import/require line, which often differs by project. For example, some project readmes say, const foo = require('apple'); while others say, const foo = require('apple')(); or const foo = require('apple').banana; The examples in the link start me off somewhere in the middle of a codebase without any context as to how I got there. I can probably make an educated _guess_ that the require is bare, but by starting in the middle rather than the beginning with the JS snippet I start off the discovery process with uncertainty. Globals are even more complicated with the import being something like <script ...>.

It would help if the Code heading was named JavaScript Library Usage Example or something and the Declaration heading was TypeScript Definition File (though Declaration may be clear enough). Because JavaScript and TypeScript look pretty similar, it is not always clear when reading documentation which I'm being shown, and explicitly stating that I'm being shown example JS code it once again removes that uncertainty.

That page appears to be mixing "How to create definition files" and "how to TypeScript". Type aliases, type unions, etc. feel like they belong in a separate document. When I go searching, that stuff is generally easy to find via Google/SO and it hasn't changed many times over the life of TypeScript so you don't come up with hundreds of wrong answers. I think there is value in having documentation that focuses _exclusively_ on how to correctly author definition files, not how to TypeScript in general.

Some of the sections also seem to be missing some information. The "Organizing Types" section, for example, shows how to create the LogOptions and AlertOptions, but not how to reference them in the definition for Greeter.log and Greeter.alert (which I believe are class member functions). Whether I need to do log(options: GreetingLib.LogOutions) or log(options: LogOptions) is nut immediately clear. Also, what if GreetingLib itself is a module or a namespace for my Greeter class? Did I import Greeter class with import { Greeter } from 'greeting'; or did I do import * as Greeter from 'greeting';? What if I want to define a variable (before passing it into the function)? How do I access GreetingLib.LogOptions from TypeScript?

Some of the above bleeds into "how to interop with JavaScript libraries. I very much prefer the import { Class } from 'library'; but I haven't seen anywhere that tells me when I can do that vs when I have to do import * as Class from 'library';.


Note: don't get me wrong, _any_ documentation is an improvement. The above is meant to provide hopefully useful user feedback.

All 8 comments

The problem is there are so many ways to write modules that it's hard to map it to .d.ts files by explaining the implementation side.

The opposite way, defining how it's used from consumption, would be more tractable. We've started some work here https://github.com/RyanCavanaugh/dts-writing but it's slow-going.

Bumping this since I came back to TypeScript after being away for a while and once again I find myself spending hours just trying to figure out how to setup a d.ts for a node module. 😢 The lack of documentation on this topic is by far the single largest TypeScript pain point and anytime I try to sell someone on TypeScript I second guess myself because I know as soon as they try to write a definition file they are in for a world of pain that I can't reasonably help them with.

If I were in charge of TypeScript roadmap (which I obviously am not) I would dedicate whatever resources are necessary to making this less painful, above all other features. Be it tools, better documentation, examples, whatever it takes to make it so any JS developer can quickly and easily figure out how to create definition files for their favorite JS library.

In a feeble attempt to be mildly useful rather than continuing to complain, I think the thing that I want to see more than anything else is something that shows me a snippet of JavaScript like I would see in a package's README.md, and then shows me how to write a definition file for it. Ideally there would be a bunch of examples like this and I can just browse until I see one that seems to align with my target package. In almost all cases I'm going from npmjs README to TypeScript definition file.

@MicahZoltu is this similar to what you're looking for? https://github.com/RyanCavanaugh/dts-writing/blob/master/By%20Example.md

No, because they are all missing the import/require line, which often differs by project. For example, some project readmes say, const foo = require('apple'); while others say, const foo = require('apple')(); or const foo = require('apple').banana; The examples in the link start me off somewhere in the middle of a codebase without any context as to how I got there. I can probably make an educated _guess_ that the require is bare, but by starting in the middle rather than the beginning with the JS snippet I start off the discovery process with uncertainty. Globals are even more complicated with the import being something like <script ...>.

It would help if the Code heading was named JavaScript Library Usage Example or something and the Declaration heading was TypeScript Definition File (though Declaration may be clear enough). Because JavaScript and TypeScript look pretty similar, it is not always clear when reading documentation which I'm being shown, and explicitly stating that I'm being shown example JS code it once again removes that uncertainty.

That page appears to be mixing "How to create definition files" and "how to TypeScript". Type aliases, type unions, etc. feel like they belong in a separate document. When I go searching, that stuff is generally easy to find via Google/SO and it hasn't changed many times over the life of TypeScript so you don't come up with hundreds of wrong answers. I think there is value in having documentation that focuses _exclusively_ on how to correctly author definition files, not how to TypeScript in general.

Some of the sections also seem to be missing some information. The "Organizing Types" section, for example, shows how to create the LogOptions and AlertOptions, but not how to reference them in the definition for Greeter.log and Greeter.alert (which I believe are class member functions). Whether I need to do log(options: GreetingLib.LogOutions) or log(options: LogOptions) is nut immediately clear. Also, what if GreetingLib itself is a module or a namespace for my Greeter class? Did I import Greeter class with import { Greeter } from 'greeting'; or did I do import * as Greeter from 'greeting';? What if I want to define a variable (before passing it into the function)? How do I access GreetingLib.LogOptions from TypeScript?

Some of the above bleeds into "how to interop with JavaScript libraries. I very much prefer the import { Class } from 'library'; but I haven't seen anywhere that tells me when I can do that vs when I have to do import * as Class from 'library';.


Note: don't get me wrong, _any_ documentation is an improvement. The above is meant to provide hopefully useful user feedback.

Oh, also all of the examples on that page are missing any export lines which I'm pretty sure are required in almost all cases, and are very often the piece that is most confusing.

I guess I have a hard time distinguishing the two. Part of writing a good .d.ts file is organizing the types in a coherent way, but maybe that's too advanced for the audience that the document needs to target.

I agree the examples there need to show more about how to work with modules.

I think there is a big difference between "writing good definitions" and "just being able to write a definition at all". Right now, the big barrier is just getting _something_ to work with my project. Usually I have some JS library that I need one or two functions from and I want my auto-complete to work on it. I'm not looking to author large complex definition files in this context.

I do think there is value in _also_ having some best practices and guidance available for how to write good/quality definition files for the times when I _am_ writing a large one and want it to work well. I'm just not sure if it is within scope for a document titled like, "Go here if you are trying to make a JS module off NPM have auto-complete" (which is what I want).

Should be covered by https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html.

@MicahZoltu please take a look and let us know if there are other additions you want to see. Also PRs to https://github.com/Microsoft/TypeScript-Handbook are always welcomed.

Was this page helpful?
0 / 5 - 0 ratings