You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Sorbet中是否存在等价于TypeScript Pick的类型工具?

Sorbet 中实现 TypeScript Pick 等效能力的方案

Sorbet 作为名义类型系统,原生没有提供和 TypeScript 结构类型体系下的 Pick 完全对等的内置工具类型,针对 T::Struct 返回字段子集的场景,有两种可落地的类型安全实现方式:

  • 手动定义子集对应的 T::Struct 类型
    这是 Sorbet 官方推荐的标准写法,完全符合 Sorbet 的类型设计范式,类型检查可以做到100%覆盖:

    # 原结构体定义
    class User < T::Struct
      const :id, Integer
      const :name, String
      const :mobile, String
      const :internal_tag, String
    end
    
    # 等效于 Pick<User, 'id' | 'name'> 的公开信息类型
    class UserPublicProfile < T::Struct
      const :id, Integer
      const :name, String
    end
    
    sig { params(user: User).returns(UserPublicProfile) }
    def extract_public_profile(user)
      UserPublicProfile.new(
        id: user.id,
        name: user.name
      )
    end
    

    该方案没有元编程开销,类型校验严格,唯一的缺点是如果需要的字段子集组合较多,会产生额外的结构体定义代码。

  • 封装通用选取方法 + 泛型标注
    如果需要减少重复的结构体定义,可以封装通用的字段选取工具方法,结合 Sorbet 泛型做类型约束,适合对类型严格度要求不极致的场景:

    module StructUtils
      extend T::Sig
      extend T::Generic
    
      sig {
        type_parameters(:Source, :PickedKey)
        .params(
          source: T.all(T::Struct, T.type_parameter(:Source)),
          picked_keys: T::Array[T.type_parameter(:PickedKey)]
        )
        .returns(T::Hash[T.type_parameter(:PickedKey), T.untyped])
      }
      def self.pick_fields(source, picked_keys)
        serialized = source.serialize(stringify_keys: false)
        picked_keys.to_h { |key| [key, serialized[key]] }
      }
    end
    
    # 调用示例
    user = User.new(id: 2, name: "Li Si", mobile: "13xxxxxxxxx", internal_tag: "test")
    public_data = StructUtils.pick_fields(user, [:id, :name])
    

    注意:受 Sorbet 类型系统能力限制,该方案无法自动推导选中字段对应值的精确类型,返回值的值类型会被标记为T.untyped,如果需要强类型校验,优先选择第一种手动定义结构体的方案。

补充说明:不要尝试用元编程动态生成 T::Struct 子类来模拟自动派生 Pick 类型,这类动态定义的结构无法被 Sorbet 静态扫描识别,会直接丢失类型检查能力。


内容的提问来源于stack exchange,提问作者Impirator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:30:45