11

I have a Node C++ Addon that provides a wrapped class similar to the one in the Node documentation. I can require() my addon and then get the constructor for my class to create an instance.

const { MyClass } = require('myaddon');
const obj = new MyClass('data');

Now I want to use TypeScript to do the same. I can't find the right combination of .d.ts file and import statement to make this work. I guess ideally I'd like to declare my class is in the module and has a constructor that takes a string. I could then just do:

import { MyClass } from 'myaddon';
const obj = new MyClass('data');

Any examples of this that people have seen?

Doug Schaefer
  • 515
  • 3
  • 10

4 Answers4

17

I think I finally have it. As suggested by @ZachB, I created a myaddon.ts file that has the following:

const myaddon = require('./build/release/myaddon')

export interface MyClass {
    myMethod(arg: string): number
}

export var MyClass: {
    new(param: string): MyClass
} = myaddon.MyClass

Then use it:

import { MyClass } from 'myaddon'

const thing: MyClass = new MyClass('something')
const answer: number = thing.myMethod('blah')
Doug Schaefer
  • 515
  • 3
  • 10
4

There are perhaps better ways of doing this, but I use the following pattern:

// bindings.ts
// Declare the interface of your addon:
export interface MyBindings {
    myMethod1: (arg1: number) => null;
}
// Load it with require
var myClass: MyBindings = require("./build/release/myaddon");
export default myClass;

And then use it from other parts of my module with import bindings from "../bindings".

ZachB
  • 13,051
  • 4
  • 61
  • 89
1

If you need to do an ambient declaration, (as I did because I'm using Node-Gyp + Webpack), you can add a mymodule.d.ts:

declare module "*mymodule.node" {
    declare class SpaceItem {}

    declare class Item extends SpaceItem {
        GetItemName(): number;
        CreateMesh(StepData, FormNote, RegDuplicate?);
    }

    var Enabler: {
        EnableMathModules(string, string);
    };
}

And then require this

import mymodule from '../build/Release/mymodule.node';
Nick Kallen
  • 97
  • 1
  • 4
  • I'm a little confused. Do you add this to the client app (for instance an Electron app that consumes the extension) or do you add this to the folder where the addon is? And where exactly do you place this file in the project folder? – Hari Mahadevan Aug 17 '21 at 03:42
  • node doesn't support `import ...` for native modules – Gurwinder Singh Dec 18 '22 at 16:56
0

Another way to do this is similiar to Nick Kallen's way.

You're basically using a naming trick. If you do:

import test = require("../test/build/Release/hello.node");

When 'compiled' to javascript, it will see the file as hello.node. Typescript will see the file as its name + a typescript file extension.

So this is how your *.node directory should look:

-hello.node

-hello.node.d.ts

-if-windows-hello.dll

In my hello.node.d.ts file I have:

export const hello: () => string;
boocs
  • 456
  • 1
  • 3
  • 5