diff --git a/rosidl_generator_py/package.xml b/rosidl_generator_py/package.xml
index 19ad032c..6d931c7c 100644
--- a/rosidl_generator_py/package.xml
+++ b/rosidl_generator_py/package.xml
@@ -41,6 +41,7 @@
ament_index_python
python3-numpy
+ python3-typing-extensions
rosidl_cli
rosidl_generator_c
rosidl_parser
diff --git a/rosidl_generator_py/resource/_action.py.em b/rosidl_generator_py/resource/_action.py.em
index 50167f34..0a081993 100644
--- a/rosidl_generator_py/resource/_action.py.em
+++ b/rosidl_generator_py/resource/_action.py.em
@@ -79,32 +79,42 @@ class Metaclass_@(action.namespaced_type.name)(rosidl_pycommon.interface_base_cl
@(module_name).Metaclass_@(action.feedback_message.structure.namespaced_type.name).__import_type_support__()
+class _@(action.namespaced_type.name)_Impl(rosidl_pycommon.interface_base_classes.BaseImpl[
+ @(action.send_goal_service.namespaced_type.name),
+ @(action.get_result_service.namespaced_type.name),
+ @(action.feedback_message.structure.namespaced_type.name)
+]):
+
+ # The send_goal service using a wrapped version of the goal message as a request.
+ SendGoalService: TypeAlias = @(action.send_goal_service.namespaced_type.name)
+ # The get_result service using a wrapped version of the result message as a response.
+ GetResultService: TypeAlias = @(action.get_result_service.namespaced_type.name)
+ # The feedback message with generic fields which wraps the feedback message.
+ FeedbackMessage: TypeAlias = @(action.feedback_message.structure.namespaced_type.name)
+
+ # The generic service to cancel a goal.
+ from action_msgs.srv._cancel_goal import CancelGoal
+ CancelGoalService: TypeAlias = CancelGoal
+ # The generic message for get the status of a goal.
+ from action_msgs.msg._goal_status_array import GoalStatusArray
+ GoalStatusMessage: TypeAlias = GoalStatusArray
+
+
class @(action.namespaced_type.name)(rosidl_pycommon.interface_base_classes.BaseAction[
@(action.goal.structure.namespaced_type.name),
@(action.result.structure.namespaced_type.name),
- @(action.feedback.structure.namespaced_type.name)
+ @(action.feedback.structure.namespaced_type.name),
+ _@(action.namespaced_type.name)_Impl
], metaclass=Metaclass_@(action.namespaced_type.name)):
# The goal message defined in the action definition.
- Goal: type[@(action.goal.structure.namespaced_type.name)] = @(action.goal.structure.namespaced_type.name)
+ Goal: TypeAlias = @(action.goal.structure.namespaced_type.name)
# The result message defined in the action definition.
- Result: type[@(action.result.structure.namespaced_type.name)] = @(action.result.structure.namespaced_type.name)
+ Result: TypeAlias = @(action.result.structure.namespaced_type.name)
# The feedback message defined in the action definition.
- Feedback: type[@(action.feedback.structure.namespaced_type.name)] = @(action.feedback.structure.namespaced_type.name)
-
- class Impl:
-
- # The send_goal service using a wrapped version of the goal message as a request.
- from @('.'.join(action.namespaced_type.namespaces)).@(module_name) import @(action.send_goal_service.namespaced_type.name) as SendGoalService
- # The get_result service using a wrapped version of the result message as a response.
- from @('.'.join(action.namespaced_type.namespaces)).@(module_name) import @(action.get_result_service.namespaced_type.name) as GetResultService
- # The feedback message with generic fields which wraps the feedback message.
- from @('.'.join(action.namespaced_type.namespaces)).@(module_name) import @(action.feedback_message.structure.namespaced_type.name) as FeedbackMessage
+ Feedback: TypeAlias = @(action.feedback.structure.namespaced_type.name)
- # The generic service to cancel a goal.
- from action_msgs.srv._cancel_goal import CancelGoal as CancelGoalService
- # The generic message for get the status of a goal.
- from action_msgs.msg._goal_status_array import GoalStatusArray as GoalStatusMessage
+ Impl: TypeAlias = _@(action.namespaced_type.name)_Impl
# Should eventually be typing.NoReturn. See mypy#14044
def __init__(self) -> None:
diff --git a/rosidl_generator_py/resource/_srv.py.em b/rosidl_generator_py/resource/_srv.py.em
index 7ac6e12e..3320ff22 100644
--- a/rosidl_generator_py/resource/_srv.py.em
+++ b/rosidl_generator_py/resource/_srv.py.em
@@ -23,6 +23,18 @@ TEMPLATE(
package_name=package_name, interface_path=interface_path,
message=service.event_message, import_statements=import_statements,
type_annotations_import_statements=type_annotations_import_statements)
+
+# Can be removed in rhel10 since TypeAlias will exist in typing
+TYPE_ALIAS_IMPORT = 'from typing_extensions import TypeAlias'
+}@
+@[if TYPE_ALIAS_IMPORT not in type_annotations_import_statements]@
+
+
+if typing.TYPE_CHECKING:
+ @(TYPE_ALIAS_IMPORT)
+@[end if]@
+@{
+type_annotations_import_statements.add(TYPE_ALIAS_IMPORT)
}@
@@ -60,9 +72,9 @@ class @(service.namespaced_type.name)(rosidl_pycommon.interface_base_classes.Bas
@(service.request_message.structure.namespaced_type.name),
@(service.response_message.structure.namespaced_type.name)
], metaclass=Metaclass_@(service.namespaced_type.name)):
- Request: type[@(service.request_message.structure.namespaced_type.name)] = @(service.request_message.structure.namespaced_type.name)
- Response: type[@(service.response_message.structure.namespaced_type.name)] = @(service.response_message.structure.namespaced_type.name)
- from @('.'.join(service.namespaced_type.namespaces)).@(module_name) import @(service.event_message.structure.namespaced_type.name) as Event
+ Request: TypeAlias = @(service.request_message.structure.namespaced_type.name)
+ Response: TypeAlias = @(service.response_message.structure.namespaced_type.name)
+ Event: TypeAlias = @(service.event_message.structure.namespaced_type.name)
# Should eventually be typing.NoReturn. See mypy#14044
def __init__(self) -> None: