Skip to main content

On This Page

T-Ruby: Implementing TypeScript-Style Static Typing for Pure Ruby Applications

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

T-Ruby: Adding Static Typing to Ruby Without Runtime Overhead

T-Ruby is an experimental tool that compiles typed code down to pure, undecorated Ruby with zero runtime overhead. It acts as a layer on top of the language where developers write RBS-inspired code that is eventually compiled into standard Ruby.

Why This Matters

While Ruby developers have access to RBS and Sorbet, typing is often treated as an optional documentation task rather than a core requirement, leading to static checks being ignored in CI/CD pipelines. T-Ruby shifts this paradigm by behaving like TypeScript, ensuring that type-correctness is verified at compile-time before the final pure Ruby product is generated. This approach aims to reduce the friction of maintaining separate type files, though the current implementation is in a technical preview phase where stability remains a challenge for production environments.

Key Insights

  • T-Ruby compiles typed code into standard Ruby files, mirroring the TypeScript-to-JavaScript build workflow.
  • The tool uses a CLI utility called trc to initialize projects and manage the compilation of *.trb source files into a destination folder.
  • Type definitions in T-Ruby allow for strict defining of Proc structures and method signatures directly within the class logic.
  • Post-compile commands can be configured to automatically trigger test suites like RSpec or Minitest upon successful compilation.
  • The project is currently in a technical preview phase as of 2026, with experimental support for Rails application structures.

Working Examples

An example of T-Ruby syntax used to create a typed HTTP client for fetching GitHub release data.

require "httparty"
require "json"
require "time"
class RubyVersion
API_URL = "https://api.github.com/repos/ruby/ruby/releases/latest"
class Response
attr_reader :code: Integer
attr_reader :json: Hash<String, untyped>
def initialize(code: Integer, json: Hash<String, untyped>): nil
@code = code
@json = json
end
def success?: Boolean
(200..299).include?(@code)
end
end
def fetch_response: Response
http = HTTParty.get(API_URL, headers: { 'User-Agent' => 'static-typing-demo' })
Response.new(http.code.to_i, JSON.parse(http.body))
end
def self.fetch(printer: Proc<[String, String, Time], nil>): nil
resp = new.fetch_response
raise "HTTP #{resp.code}" unless (200..299).include?(resp.code)
data = resp.json
published = Time.parse((data['published_at'] || Time.now.utc.iso8601).to_s)
printer.call((data['tag_name'] || data['name']).to_s, data['html_url'], published)

end
end

Practical Applications

  • Compiling typed *.trb files into a /dist folder for deployment to standard Ruby environments without runtime dependencies.
  • Using the trc —init configuration to automate the execution of RSpec tests immediately following a successful type-check and build.
  • Managing Rails applications by placing the app folder within a T-Ruby source directory to facilitate a TypeScript-like build process.

References:

Continue reading

Next article

Two Color Schemes, Four Modes: Native CSS Theme Switching

Related Content