从TypeScript迁移到Sorbet:类型系统对比指南
前言
对于熟悉TypeScript的开发者来说,学习Sorbet类型系统可能会遇到一些困惑。本文将从TypeScript开发者的角度,系统性地介绍Sorbet的类型系统特性及其与TypeScript的对应关系,帮助开发者快速掌握Sorbet的核心概念。
基础类型对比
原始类型
在TypeScript中,我们使用string
、number
、boolean
等表示基本类型,而在Sorbet中:
string
→String
:Ruby中所有字符串都是String类的实例number
→Integer
/Float
/Numeric
:Ruby将数字类型细分为多个类boolean
→T::Boolean
:这是TrueClass
和FalseClass
的联合类型
集合类型
处理数组和映射时:
string[]
→T::Array[String]
:Sorbet使用泛型语法Record<K,V>
/Map<K,V>
→T::Hash[K,V]
:Ruby中使用Hash类实现键值映射
类型系统特性对比
类型注解
TypeScript使用冒号语法进行类型注解,而Sorbet使用特殊方法:
// TypeScript
let name: string = "Alice";
# Sorbet
name = T.let("Alice", String) # 同时进行静态和运行时检查
联合与交叉类型
number | string
→T.any(Integer, String)
MyClass & MyInterface
→T.all(MyClass, MyInterface)
注意:Sorbet是名义类型系统,与TypeScript的结构化类型系统不同。
可选与可为空类型
TypeScript有?
和| null
两种方式表示可为空,而Sorbet统一使用:
T.nilable(String) # 相当于TypeScript中的 string | null
类型操作与流程控制
类型检查
TypeScript使用typeof
和instanceof
,Ruby/Sorbet使用:
if x.is_a?(String) # 类型检查
# 或
case x
when String then # ...
end
安全导航操作符
两者都支持安全导航:
// TypeScript
x?.foo
# Ruby/Sorbet
x&.foo
空值合并
TypeScript的??
在Ruby中可近似为:
x.nil? ? y : x # 精确等价
x || y # 近似等价,但会处理false情况
高级类型特性
类型别名
// TypeScript
type AorB = A | B;
# Sorbet
AorB = T.type_alias { T.any(A, B) }
结构体类型
TypeScript使用内联对象类型,Sorbet使用T::Struct:
class Thing < T::Struct
prop :x, Integer
prop :y, T.nilable(String)
end
类型断言
// TypeScript
let x = expr as Type;
# Sorbet
x = T.cast(expr, Type) # 同时进行静态和运行时检查
特殊类型
any
→T.untyped
:表示任意类型unknown
→T.anything
:表示未知类型never
→T.noreturn
:表示永远不会返回的类型
差异与注意事项
- 字面量类型:Sorbet没有直接等价于TypeScript字面量类型的特性,建议使用枚举替代
- 类型谓词:Sorbet不支持TypeScript的类型谓词功能
- 鉴别联合:Sorbet通过密封类(Sealed Classes)实现类似功能
总结
虽然Sorbet和TypeScript在类型系统上有许多相似之处,但由于Ruby和JavaScript语言特性的差异,它们在实现细节上存在显著区别。理解这些差异有助于TypeScript开发者更快地上手Sorbet,并在Ruby项目中有效地使用静态类型检查。
建议开发者在实际使用中结合Sorbet文档,逐步掌握其类型系统的独特之处,充分发挥静态类型在Ruby项目中的优势。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考