Search code examples
typescripttypesairtable

Importing types alongside main import with import/require


I'm writing a definition file for airtable, and unfortunately, they are exporting only one class like this:

...

module.exports = Airtable;

So, my airtable.d.ts file looks like this:

declare module "airtable" {
    export type MyType = { ... };

    export class Airtable {
        ...
    }

    export = Airtable;
}

When I'm importing the Airtable class it works great:

import Airtable = require("airtable");
...
new Airtable(...)

But I can't find a way to import MyType as well:

let a: Airtable.MyType;

Results in this error:

'Airtable' only refers to a type, but is being used as a namespace here

And:

import { MyType } from "airtable";

Results in these errors:

Module "airtable" has no exported member 'MyType'
Module "airtable" resolves to a non-module entity and cannot be imported using this construct

Any idea how I can import other exported types while keep using export = and import/require?
Thanks.


Solution

  • So the answer really depends on how you're going to use the types. If you're using them in your own project, you need a file (called <whatever>.d.ts) that declares a module called "airtable". In that, you'll need to export something. Since you're exporting a class, you have to use the export = X syntax rather than export X because you're changing the entire export object rather than adding a property. on the export object (more on that in a sec). As for the types, outside the module in your .d.ts file, you can also decalre a type that will become globally available. If that rubs you the wrong way (or you're worried about conflicts), you can put your type into a module as well. Since it's a typescript-only thing, it doesn't have to be backed by any js code. You can then import/export it like normal:

    // my.d.ts
    
    declare module 'airtable' {
      class Airtable {
        constructor(opts?: MyType)
      }
      export = Airtable
    }
    
    declare type MyType = string | number
    
    declare module 'AirtableTypes' {
      export type MyString = string
      export type MyNumber = number
    }
    

    and usage

    // index.ts
    import Airtable from 'airtable'
    import AirtableTypes from 'AirtableTypes'
    
    const a = new Airtable('a')
    
    const n: MyType = 3
    
    const s: AirtableTypes.MyString = '3'
    

    If you want to add types to DefinitelyTyped (which I'm sure they would appreciate!) you can follow the guide here to author the declaration file.

    It'll point you at

    You (correctly) noted that Airtable exports a single class, which doesn't play super nicely with TS. There's some discussion here. Either way, the above guide will point you at module-class.d.ts, which lets you declare an exported class and accompanying types. You couldn't use this above, as the format is only available when definition files live in the module root or @types/<module>.

    /*~ This declaration specifies that the class constructor function
     *~ is the exported object from the file
     */
    export = Airtable
    
    /*~ Write your module's methods and properties in this class */
    declare class Airtable {
      constructor(opts?: Airtable.AirtableMethodOptions)
    }
    
    /*~ If you want to expose types from your module as well, you can
     *~ place them in this block.
     */
    declare namespace Airtable {
      export interface AirtableMethodOptions {
        endpointUrl: string
      }
    }