如何用Sorbet定义类似TS/Rust的泛型Result结构体?
在Sorbet中实现泛型Result联合类型
可以实现你想要的泛型Result类型,无需给Success和Failure类添加多余的泛型参数。通过Sorbet的泛型类型别名,就能封装Success[T] | Failure[E]的联合类型,实现类似Result[T, E]的简洁写法。
实现方案
保留你现有Success和Failure泛型类的基础上,定义一个泛型类型别名Result来封装联合类型:
# typed: strict # frozen_string_literal: true module Core module Type class Success extend T::Sig extend T::Generic ValueType = type_member sig { returns(ValueType) } attr_reader :value sig { params(value: ValueType).void } def initialize(value) @value = value end end class Failure extend T::Sig extend T::Generic ErrorType = type_member sig { returns(ErrorType) } attr_reader :error sig { params(error: ErrorType).void } def initialize(error) @error = error end end # 定义泛型Result类型别名,封装Success和Failure的联合类型 Result = T.type_alias do T::Generic.type_parameters(:T, :E) do |T, E| T.any(Success[T], Failure[E]) end end end end extend T::Sig # 直接使用Result[T, E]作为返回类型,符合你的目标写法 sig { params(value: Integer).returns(Core::Type::Result[Integer, String]) } def zero?(value) if value.zero? Core::Type::Success.new(value) else Core::Type::Failure.new("It is not zero") end end result = zero?(0) case result when Core::Type::Success p result.value # Sorbet可正确推断value为Integer类型 when Core::Type::Failure p result.error # Sorbet可正确推断error为String类型 end
方案说明
- 避免了
dry-monads中给Success/Failure强制添加双泛型参数的hack写法,保持类的单一职责:Success仅关注成功值类型,Failure仅关注错误类型。 - 泛型类型别名
Result接收两个类型参数T(成功值类型)和E(错误类型),内部直接映射为对应泛型实例的联合类型。 - Sorbet对该写法完全支持,类型检查和分支推断均能正常工作,比如case分支中会自动识别对应类型的属性类型。
内容的提问来源于stack exchange,提问作者Rostislav Zhuravsky
相关产品推荐
相关产品推荐

