Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript - can't augment a module

I'm developing a personal project using typescript v3.6.4 and twitter API (twit).

I've also installed @types/twit from https://www.npmjs.com/package/@types/twit

I want to make a request to a 'lists/members' endpoint.

My code is:

import Twit from "twit";

const client = new Twit(...);

client.get('lists/members', {list_id: '123123'})

But, typescript gives me an error:

src/data/TwitterProvider.ts:16:34 - error TS2769: No overload matches this call.
  Overload 1 of 3, '(path: string, callback: Callback): void', gave the following error.
    Argument of type '{ list_id: string; }' is not assignable to parameter of type 'Callback'.
      Object literal may only specify known properties, and 'list_id' does not exist in type 'Callback'.
  Overload 2 of 3, '(path: string, params?: Params): Promise<PromiseResponse>', gave the following error.
    Argument of type '{ list_id: string; }' is not assignable to parameter of type 'Params'.
      Object literal may only specify known properties, and 'list_id' does not exist in type 'Params'.

     client.get('lists/members', {list_id: 'test'})

Which makes sense, since there's no list_id property in https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/twit/index.d.ts file

I did some research and created ./src/@types/twit.d.ts:

import "twit";
declare module 'twit' {
  namespace Twit {
    interface Params {
      list_id?: string;
    }
  }
}

However I still get the same error.

My tsconfig.json:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "dist",
    "rootDir": "src",
    "sourceMap": true
  },
  "typeRoots": [
    "src/@types",
    "node_modules/@types"
  ],
  "include": [
    "src/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

And I'm running the code by ts-node src/index.ts

like image 606
Fen1kz Avatar asked Sep 08 '26 23:09

Fen1kz


1 Answers

Your module augmentation approach would work in general for "standard" npm package declarations. In case of twit module augmentation unfortunately is not possible (or I am not aware of a proper way to do it).

Twit is exported as a CommonJS module via export = Twit syntax.

Default exports are meant to act as a replacement for this behavior; however, the two are incompatible. TypeScript supports export = to model the traditional CommonJS and AMD workflow.

TypeScript apparently only allows module augmentation of ES modules (see example down under), above syntax explicitly creates a Node CommonJS default export. This Node module system implementation deviates in some ways from the original CommonJS standard, which is e.g. used for Babel and TypeScript compiler output.

For example the Node implementation allows to export a single default object via modules.exports = ..., whereas the CommonJS specifiction only permits to add properties and methods to the exports object like export.foo = ... (more info on ES and CommonJS module import conversions here and here.

tl;dr: I tested module augmentation for Node CommonJS export (neglecting namespaces inside modules here, as it is an anti-pattern).

lib.d.ts:

declare module "twit3" {
  class Twit3 { bar(): string; }
  export = Twit3;
}

index.ts:

import Twit3 from "twit3";

// Error: Cannot augment module 'twit3' because it resolves to a non-module entity.
declare module "twit3" {
  class Twit3 { baz(): string; }
}

Codesandbox

... did not work out. Replacing the export = syntax with a named export made the sample compile (default exports cannot be augmented in general).

How to solve that?

Create a ticket/PR for twit, if it is really a missing Params option. In the meanwhile a workaround like this could preserve strong types for additional properties, while still adding list_id option to the runtime:

const yourOtherParams: Params = {/* insert here */}
client.get("lists/members", { ...yourOtherParams , ...{ list_id: "123123" } });

// or cast directly
client.get("lists/members", { list_id: "123123" } as Params);

Hope, it helps!

like image 142
ford04 Avatar answered Sep 10 '26 14:09

ford04



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!