Skip to content

Infer concrete types from constructor TypeClass forms#1526

Merged
minggangw merged 4 commits into
RobotWebTools:developfrom
minggangw:fix-1525
Jun 3, 2026
Merged

Infer concrete types from constructor TypeClass forms#1526
minggangw merged 4 commits into
RobotWebTools:developfrom
minggangw:fix-1525

Conversation

@minggangw
Copy link
Copy Markdown
Member

@minggangw minggangw commented Jun 2, 2026

Support the constructor form of TypeClass (the value returned by rclnodejs.require(...)) with full type inference for messages, services, and actions, bringing it on par with the existing string and object-descriptor forms, and make the runtime loader accept that form so it works end to end.

Types

  • TypeClass now recognizes message, service ({ Request, Response }), and action ({ Goal, Feedback, Result }) constructor shapes (types/node.d.ts, types/service.d.ts, types/action_client.d.ts).
  • ServiceRequestMessage / ServiceResponseMessage and ActionGoal / ActionFeedback / ActionResult infer the concrete payload types from the constructor.
  • ServiceType / ActionType and the rostsd_gen generator (rostsd_gen/index.js) handle the constructor form.

Runtime

  • lib/interface_loader.js: loadInterface() accepts an already-loaded interface constructor and returns it as-is (idempotent), validated via the generated class's static type() method. Arbitrary functions still fall through to the existing MESSAGE_NOT_FOUND error. This fixes the MESSAGE_NOT_FOUND failure when a constructor was passed to ActionServer / ActionClient, which call loadInterface unconditionally.

Tests

  • test/types/index.test-d.ts: tsd coverage for every TypeClass form — message, service, and action via constructor, string, and object descriptor.
  • test/test-action-server.js, test/test-service.js: runtime regression tests that pass the constructor form to ActionServer / ActionClient and createService / createClient and exercise a full round-trip.
  • test/test-message-type.js: unit tests for loadInterface() idempotency and the arbitrary-function rejection path.

Demos

  • topics, services, and actions TypeScript demos updated to demonstrate both the string-name and message/service/action-class styles, with typed callbacks via typeof Ctor.
  • All three demos depend on the local rclnodejs (file:../../..) and document npm install --ignore-scripts; README source examples use the current LTS (Lyrical).

Fix: #1525

Copilot AI review requested due to automatic review settings June 2, 2026 06:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves TypeScript type inference when using “constructor-form” ROS interfaces (e.g., values returned by rclnodejs.require(...)) so that publishers/subscriptions/services/actions can infer concrete message/request/response/goal types instead of falling back to object.

Changes:

  • Extend conditional types to infer request/response and goal/feedback/result types from constructor-form service/action TypeClass values.
  • Update the generated TS mapping types in rostsd_gen to recognize constructor-form types.
  • Add tsd type tests and update the TypeScript demos to illustrate string vs constructor usage.

Reviewed changes

Copilot reviewed 4 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
types/service.d.ts Adds constructor-form inference for service request/response message types.
types/node.d.ts Expands TypeClass forms to include service/action constructor-like shapes and adds guidance for descriptor form.
types/action_client.d.ts Adds constructor-form inference for action goal/feedback/result types.
test/types/index.test-d.ts Adds tsd coverage for constructor-form message/service/action typing.
rostsd_gen/index.js Updates generated MessageType/ServiceType/ActionType conditional mappings to support constructor-form inference.
demo/typescript/topics/src/subscriber.ts Documents and demonstrates subscription typing via string vs constructor forms.
demo/typescript/topics/src/publisher.ts Documents and demonstrates publisher typing via string vs constructor forms.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rostsd_gen/index.js
Comment on lines 192 to 197
fs.writeSync(fd, ' type ServiceTypeClassName = keyof ServicesMap;\n');
fs.writeSync(fd, ' type Service = ServicesMap[ServiceTypeClassName];\n');
fs.writeSync(
fd,
' type ServiceType<T> = T extends ServiceTypeClassName ? ServicesMap[T] : object;\n\n'
' type ServiceType<T> = T extends ServiceTypeClassName ? ServicesMap[T] : T extends { Request: any; Response: any } ? T : object;\n\n'
);
Comment thread rostsd_gen/index.js
Comment on lines 205 to 210
fs.writeSync(fd, ' type ActionTypeClassName = keyof ActionsMap;\n');
fs.writeSync(fd, ' type Action = ActionsMap[ActionTypeClassName];\n');
fs.writeSync(
fd,
' type ActionType<T> = T extends ActionTypeClassName ? ActionsMap[T] : object;\n\n'
' type ActionType<T> = T extends ActionTypeClassName ? ActionsMap[T] : T extends { Goal: any; Feedback: any; Result: any } ? T : object;\n\n'
);
@coveralls
Copy link
Copy Markdown

coveralls commented Jun 2, 2026

Coverage Status

coverage: 85.523% (+0.03%) from 85.492% — minggangw:fix-1525 into RobotWebTools:develop

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 19 out of 22 changed files in this pull request and generated 3 comments.

Comment thread rostsd_gen/index.js
Comment on lines 193 to 197
fs.writeSync(fd, ' type Service = ServicesMap[ServiceTypeClassName];\n');
fs.writeSync(
fd,
' type ServiceType<T> = T extends ServiceTypeClassName ? ServicesMap[T] : object;\n\n'
' type ServiceType<T> = T extends ServiceTypeClassName ? ServicesMap[T] : T extends { Request: any; Response: any } ? T : object;\n\n'
);
Comment thread rostsd_gen/index.js
Comment on lines 205 to 210
fs.writeSync(fd, ' type ActionTypeClassName = keyof ActionsMap;\n');
fs.writeSync(fd, ' type Action = ActionsMap[ActionTypeClassName];\n');
fs.writeSync(
fd,
' type ActionType<T> = T extends ActionTypeClassName ? ActionsMap[T] : object;\n\n'
' type ActionType<T> = T extends ActionTypeClassName ? ActionsMap[T] : T extends { Goal: any; Feedback: any; Result: any } ? T : object;\n\n'
);
Comment on lines +36 to 38
"dependencies": {
"rclnodejs": "file:../../.."
}
@minggangw minggangw merged commit fce926b into RobotWebTools:develop Jun 3, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Infer concrete types from constructor TypeClass forms

3 participants