diff --git a/package.json b/package.json
index a0e65f7f..24420ae1 100644
--- a/package.json
+++ b/package.json
@@ -17,14 +17,13 @@
"build:dev": "node-gyp -j 16 build --debug",
"rebuild": "npm run clean && node-gyp -j 16 rebuild",
"rebuild:dev": "npm run clean && node-gyp -j 16 rebuild --debug",
- "generate-messages": "node scripts/generate_messages.js",
- "generate-messages:dev": "node scripts/generate_messages.js --debug",
+ "generate-messages": "node scripts/generate_messages.js && node scripts/generate_tsd.js",
+ "generate-messages:dev": "node scripts/generate_messages.js --debug && node scripts/generate_tsd.js",
"clean": "node-gyp clean && rimraf ./generated",
"install": "npm run rebuild",
"postinstall": "npm run generate-messages",
"docs": "cd docs && make",
- "test": "node --expose-gc ./scripts/run_test.js && npm run dtslint",
- "dtslint": "node scripts/generate_tsd.js",
+ "test": "node --expose-gc ./scripts/run_test.js && npx tsd",
"lint": "eslint --max-warnings=0 --ext js,ts index.js types scripts lib example rosidl_gen rosidl_parser test benchmark/rclnodejs && node ./scripts/cpplint.js",
"format": "clang-format -i -style=file ./src/*.cpp ./src/*.hpp && prettier --write \"{lib,rosidl_gen,rostsd_gen,rosidl_parser,types,example,test,scripts,benchmark}/**/*.{js,md,ts}\" ./*.{js,md,ts}",
"prepare": "husky"
@@ -45,6 +44,7 @@
},
"devDependencies": {
"@babel/eslint-parser": "^7.25.9",
+ "@types/node": "^22.13.5",
"@typescript-eslint/eslint-plugin": "^8.18.0",
"@typescript-eslint/parser": "^8.18.0",
"babel-eslint": "^10.1.0",
@@ -60,6 +60,7 @@
"mocha": "^11.0.2",
"sinon": "^19.0.2",
"tree-kill": "^1.2.2",
+ "tsd": "^0.31.2",
"typescript": "^5.7.2"
},
"dependencies": {
@@ -70,17 +71,16 @@
"compare-versions": "^6.1.1",
"debug": "^4.4.0",
"dot": "^1.1.3",
- "dtslint": "^4.2.1",
"fs-extra": "^11.2.0",
- "json-bigint": "^1.0.0",
"is-close": "^1.3.3",
+ "json-bigint": "^1.0.0",
"mkdirp": "^3.0.1",
"mz": "^2.7.0",
"nan": "^2.22.0",
+ "prettier": "^3.4.2",
"rimraf": "^6.0.1",
"uuid": "^11.0.3",
- "walk": "^2.3.15",
- "prettier": "^3.4.2"
+ "walk": "^2.3.15"
},
"husky": {
"hooks": {
@@ -95,6 +95,9 @@
"clang-format -i -style=file"
]
},
+ "tsd": {
+ "directory": "test/types"
+ },
"engines": {
"node": ">= 16.13.0"
}
diff --git a/test/types/index.d.ts b/test/types/index.d.ts
deleted file mode 100644
index ed97e6f6..00000000
--- a/test/types/index.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-// Minimum TypeScript Version: 3.9
diff --git a/test/types/index.test-d.ts b/test/types/index.test-d.ts
new file mode 100644
index 00000000..7597ccd8
--- /dev/null
+++ b/test/types/index.test-d.ts
@@ -0,0 +1,392 @@
+///
+
+import { expectType } from 'tsd';
+import * as rclnodejs from 'rclnodejs';
+
+const NODE_NAME = 'test_node';
+const LIFECYCLE_NODE_NAME = 'lifecycle_test_node';
+const TYPE_CLASS = 'std_msgs/msg/String';
+const TOPIC = 'topic';
+const MSG = rclnodejs.createMessageObject(TYPE_CLASS);
+MSG.data = '';
+
+// ---- rclnodejs -----
+expectType>(rclnodejs.init());
+expectType(rclnodejs.DistroUtils.getDistroName());
+expectType(rclnodejs.isShutdown());
+expectType(rclnodejs.shutdown());
+expectType(rclnodejs.removeSignalHandlers());
+
+// ---- DistroUtil ----
+expectType(rclnodejs.DistroUtils.getDistroId());
+expectType(
+ rclnodejs.DistroUtils.getDistroId('foxy')
+);
+expectType(rclnodejs.DistroUtils.getDistroName());
+expectType(rclnodejs.DistroUtils.getDistroName(2105));
+
+// ---- Context -----
+expectType(rclnodejs.Context.defaultContext());
+
+// ---- NodeOptions ----
+const nodeOptions = new rclnodejs.NodeOptions();
+expectType(nodeOptions);
+expectType(nodeOptions.startParameterServices);
+expectType(nodeOptions.automaticallyDeclareParametersFromOverrides);
+expectType(nodeOptions.parameterOverrides);
+
+// ---- Node -----
+const node = rclnodejs.createNode(NODE_NAME);
+expectType(node);
+expectType(new rclnodejs.Node(NODE_NAME + '1'));
+expectType(node.name());
+expectType(node.namespace());
+expectType(node.getLogger());
+expectType(node.getClock());
+expectType(node.spin());
+expectType(node.spinOnce());
+expectType(node.spinning);
+expectType(node.destroy());
+expectType(
+ node.getPublisherNamesAndTypesByNode(NODE_NAME)
+);
+expectType(
+ node.getServiceNamesAndTypes()
+);
+expectType(
+ node.getServiceNamesAndTypesByNode(NODE_NAME)
+);
+expectType(
+ node.getSubscriptionNamesAndTypesByNode(NODE_NAME)
+);
+expectType(node.getTopicNamesAndTypes());
+expectType(node.getNodeNames());
+expectType(node.getNodeNamesAndNamespaces());
+expectType(node.countPublishers(TOPIC));
+expectType(node.countSubscribers(TOPIC));
+expectType>(
+ rclnodejs.Node.getDefaultOptions()
+);
+
+// ---- LifecycleNode ----
+const lifecycleNode = rclnodejs.createLifecycleNode(LIFECYCLE_NODE_NAME);
+expectType(lifecycleNode);
+
+const lifecycleNode1 = rclnodejs.createLifecycleNode(
+ LIFECYCLE_NODE_NAME + '1',
+ undefined,
+ undefined,
+ undefined,
+ true
+);
+expectType(lifecycleNode1);
+
+const lifecycleNode2 = new rclnodejs.lifecycle.LifecycleNode(
+ LIFECYCLE_NODE_NAME
+);
+expectType(lifecycleNode2);
+
+const lifecycleNode3 = new rclnodejs.lifecycle.LifecycleNode(
+ LIFECYCLE_NODE_NAME + '3',
+ undefined,
+ undefined,
+ undefined,
+ true
+);
+expectType(lifecycleNode3);
+
+expectType(lifecycleNode.currentState);
+expectType(lifecycleNode.availableStates);
+expectType(
+ lifecycleNode.transitions
+);
+expectType(
+ lifecycleNode.availableTransitions
+);
+
+const ReturnValue = new rclnodejs.lifecycle.CallbackReturnValue();
+expectType(ReturnValue);
+expectType(lifecycleNode.configure(ReturnValue));
+expectType(lifecycleNode.activate());
+expectType(lifecycleNode.deactivate());
+expectType(lifecycleNode.cleanup());
+expectType(lifecycleNode.shutdown());
+
+// ---- Publisher ----
+const publisher = node.createPublisher(TYPE_CLASS, TOPIC);
+expectType>(publisher);
+expectType