0

In my JS code I import a module like so:

const toolbox = require('../toolbox')

/**
 * @param {toolbox.Hammer} hammer
 */
function useHammer(hammer) {
  let nail = new toolbox.Nail()
  hammer.ham(nail)
}

Now, because my tools/index.d.ts file exports toolbox as a namespace. My IDE can see that hammer has a method ham on it. Awesome! But it cannot see that toolbox has a member Nail in it.

I tried placing @module and @export tags in toolbox/index.js to no avail. I also tried placing a @type {toolbox} over top of the require statement but I'm told that toolbox is referenced directly or indirectly in its own type annotation.

How can I let my IDE know that toolbox = require('toolbox') makes toolbox correspond to my namespace?


An example toolbox/index.js and toolbox/index.d.ts for reference:

exports.Hammer = class {
  ham (nail) {
    if (Math.random() > 0.1) {
      exports.nailCount -= 1
      return 'bang!' 
    } else return 'Ouch my thumb!'
  }
}
exports.nailCount = 100
exports.Nail = class {}
export = toolbox
export as namespace toolbox

declare namespace toolbox {
  class Nail {}
  class Hammer {
    ham(n: Nail) : string
  }
}

and my tsconfig for good measure (since it's a little cargo-culty)

{
  "compilerOptions": {
    "allowJs": true,
    "target": "es5",
    "checkJs": true,
    "baseUrl": "../",
    "moduleResolution": "node",
    "noEmit": true
  }
}
1
  • I should mention, though it's not essential to this question, that one of my goals is to not modify the JS files at this stage. If this could come entirely from .d.ts files that would be excellent. But it's not a show-stopper. Some JSDoc annotations are acceptable at this stage but not preferred. Commented Feb 20, 2020 at 15:16

1 Answer 1

1

Which IDE are you using?

In VS Code, I can see Nail and nailCount show up as being part of toolbox.

See this image: enter image description here

Also, to ensure hammer.ham function only accepts a Nail instance, add some property to the Nail class definition in the index.d.ts E.g.

// toolbox/index.d.ts

export = toolbox;
export as namespace toolbox;

declare namespace toolbox {
  class Nail {
    length: string; // new property added
  }
  class Hammer {
    ham(n: Nail): string;
  }
}

Now, in main/index.js we'll get an error if we pass anything other than a Nail instance. e.g.

const toolbox = require("../toolbox");

/**
 * @param {toolbox.Hammer} hammer
 */
function useHammer(hammer) {
  let nail = new toolbox.Nail();
  hammer.ham("nail-string"); // this will show a red squiggle under "nail-string" since it is a string and the compiler expected a Nail instance
}

see this image: enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Hmm, I am using VSCode, maybe there is something about the project structure that is interfering. I'll see if I can reproduce and post back.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.