George Edwards George Edwards - 3 months ago 7
TypeScript Question

Modelling (long-ish) APIs in Typescript declaration files

I am a bit confused about how you are supposed to model APIs in Typescript.

I am trying to model the hexo API, which for example usage, looks a bit like this:

hexo.extend.tag.register(name, function(args, content){
// ...
}, options);


So far I have got something which looks like this:

//hexo.d.ts
declare module 'hexo' {
namespace extend {
export class tag {
public register: _register;
}
}
}

declare class _register {
name: string;
callback(args: any, content: any);
options: _options;
}

declare class _options {
ends: boolean;
}


However, I am getting issues like:


Property 'register' does not exist on type 'typeof tag'.


So how should I model this, it seems as though Typescript becomes a bit tricky after you have declared a class in a namespace in a module, and none of those types can exist within themselves?

What would
a.b.c.d.e.f()
look like in a
.d.ts
file?

Answer

In general, something is only a class if it is called with new. Otherwise it is just a plain object. I'd do something like that:

declare module 'hexo' {
    class Hexo {
        constructor( cwd, opts )
        load() : Promise<any>
        extend : {
            console : any //declare me later, set any for now 
            // etc
            tag : {
                register(name:string, cb: (args,content) => void , opts : any)
            }
        }
    }
    export = Hexo;
}

export = something is used when the module exports a single object (class Hexo becomes the module itself, not an object inside it).

PS: callback types (and actually any type) can be referenced using the type keyword. The type keyword may even replace the interface keyword...

type someCallback = ( err : Error , resp : HttpResponse ) => Promise<any>