Type Signatures
30.1 RBS (Ruby's Official Type Signature Language)
TypeProf infers types from code. Ruby LSP uses RBS for better completion.
# sig/bank_account.rbs
class BankAccount
attr_reader owner: String
attr_reader balance: Integer
def initialize: (String owner, ?Integer balance) -> void
def deposit: (Integer amount) -> self
def withdraw: (Integer amount) -> bool
def self.accounts_created: () -> Integer
end
interface _Writer
def <<: (String) -> untyped
end
type user_id = Integer
type result[T] = { ok: true, value: T } | { ok: false, error: String }gem install rbs steep
rbs prototype rb lib/bank_account.rb > sig/bank_account.rbs # generate a skeleton
steep init && steep check # type-check with Steep
rbs collection install # signatures for gems30.2 Sorbet (Stripe's Gradual Type Checker)
Run srb tc for static checks. Sorbet also has runtime checks, Tapioca (generates RBI files for gems), and strictness levels (ignore, false, true, strict, strong). Inline RBS comments (#: (Integer) -> Integer) are increasingly supported by Sorbet and the tooling.
# typed: strict
require "sorbet-runtime"
class Calculator
extend T::Sig
sig { params(a: Integer, b: Integer).returns(Integer) }
def add(a, b) = a + b
sig { params(values: T::Array[Float]).returns(T.nilable(Float)) }
def average(values)
return nil if values.empty?
values.sum / values.size
end
end30.3 When to Use Types
Large codebases, libraries with public APIs, and teams that need refactoring safety. Adopt gradually: types complement tests, they don't replace them.