Skip to main content
Examples Verified (100%)

Type Syntax Cheatsheet

A comprehensive quick reference guide for T-Ruby type syntax. Bookmark this page for easy access to all type annotations and syntax patterns.

Basic Types

TypeDescriptionExample
StringText dataname: String = "Alice"
IntegerWhole numberscount: Integer = 42
FloatDecimal numbersprice: Float = 19.99
BooleanBoolean valuesactive: Boolean = true
SymbolImmutable identifiersstatus: Symbol = :active
nilAbsence of valuevalue: nil = nil
AnyAny type (avoid when possible)data: Any = "anything"
voidNo return valuedef log(msg: String): void

Variable Annotations

# Variable with type annotation
name: String = "Alice"
age: Integer = 30
price: Float = 99.99

# Multiple variables
x: Integer = 1
y: Integer = 2
z: Integer = 3

# Type inference (type annotation optional)
message = "Hello" # Inferred as String

Function Signatures

# Basic function
def greet(name: String): String
"Hello, #{name}!"
end

# Multiple parameters
def add(a: Integer, b: Integer): Integer
a + b
end

# Optional parameters
def greet(name: String, greeting: String = "Hello"): String
"#{greeting}, #{name}!"
end

# Rest parameters
def sum(*numbers: Integer): Integer
numbers.sum
end

# Keyword arguments
def create_user(name: String, email: String, age: Integer = 18): Hash
{ name: name, email: email, age: age }
end

# No return value
def log(message: String): void
puts message
end

Union Types

SyntaxDescriptionExample
A | BEither type A or BString | Integer
A | B | COne of multiple typesString | Integer | Boolean
T | nilOptional typeString | nil
T?Shorthand for T | nilString?
# Union types
id: String | Integer = "user-123"
id: String | Integer = 456

# Optional values
name: String | nil = nil
name: String? = nil # Shorthand

# Multiple types
value: String | Integer | Boolean = true

# Function with union return type
def find_user(id: Integer): User | nil
# Returns User or nil
end

Array Types

# Array of specific type
names: Array<String> = ["Alice", "Bob"]
numbers: Array<Integer> = [1, 2, 3]

# Array of union types
mixed: Array<String | Integer> = ["Alice", 1, "Bob", 2]

# Nested arrays
matrix: Array<Array<Integer>> = [[1, 2], [3, 4]]

# Empty array with type
items: Array<String> = []

Hash Types

# Hash with specific key and value types
scores: Hash<String, Integer> = { "Alice" => 100, "Bob" => 95 }

# Symbol keys
config: Hash<Symbol, String> = { host: "localhost", port: "3000" }

# Union value types
data: Hash<String, String | Integer> = { "name" => "Alice", "age" => 30 }

# Nested hashes
users: Hash<Integer, Hash<Symbol, String>> = {
1 => { name: "Alice", email: "alice@example.com" }
}

Generic Types

# Generic function
def first<T>(arr: Array<T>): T | nil
arr[0]
end

# Multiple type parameters
def pair<K, V>(key: K, value: V): Hash<K, V>
{ key => value }
end

# Generic class
class Box<T>
@value: T

def initialize(value: T): void
@value = value
end

def get: T
@value
end
end

# Using generics
box = Box<String>.new("hello")
result = first([1, 2, 3]) # Type inferred

Type Aliases

# Simple alias
type UserId = Integer
type EmailAddress = String

# Union type alias
type ID = String | Integer
type JSONValue = String | Integer | Float | Boolean | nil

# Collection alias
type StringList = Array<String>
type UserMap = Hash<Integer, User>

# Generic alias
type Result<T> = T | nil
type Callback<T> = Proc<T, void>

# Using aliases
user_id: UserId = 123
email: EmailAddress = "alice@example.com"

Class Annotations

# Instance variables
class User
@name: String
@age: Integer
@email: String | nil

def initialize(name: String, age: Integer): void
@name = name
@age = age
@email = nil
end

def name: String
@name
end

def age: Integer
@age
end
end

# Class variables
class Counter
@@count: Integer = 0

def self.increment: void
@@count += 1
end

def self.count: Integer
@@count
end
end

# Generic class
class Container<T>
@value: T

def initialize(value: T): void
@value = value
end

def value: T
@value
end
end

Interface Definitions

# Basic interface
interface Printable
def to_s: String
end

# Interface with multiple methods
interface Comparable
def <=>(other: self): Integer
def ==(other: self): Boolean
end

# Generic interface
interface Collection<T>
def add(item: T): void
def remove(item: T): Boolean
def size: Integer
end

# Implementing interfaces
class User
implements Printable

@name: String

def initialize(name: String): void
@name = name
end

def to_s: String
"User: #{@name}"
end
end

Type Operators

OperatorNameDescriptionExample
|UnionEither/or typesString | Integer
&IntersectionBoth typesPrintable & Comparable
?OptionalShorthand for | nilString?
<T>GenericType parameterArray<T>
=>Hash pairKey-value typeHash<String => Integer>
# Union (OR)
value: String | Integer

# Intersection (AND)
class Person
implements Printable & Comparable
end

# Optional
name: String? # Same as String | nil

# Generics
items: Array<String>
pairs: Hash<String, Integer>

Blocks, Procs, and Lambdas

# Block parameter
def each_item<T>(items: Array<T>, &block: Proc<T, void>): void
items.each { |item| block.call(item) }
end

# Proc types
callback: Proc<String, void> = ->(msg: String): void { puts msg }
transformer: Proc<Integer, String> = ->(n: Integer): String { n.to_s }

# Lambda with types
double: Proc<Integer, Integer> = ->(n: Integer): Integer { n * 2 }

# Block with multiple parameters
def map<T, U>(items: Array<T>, &block: Proc<T, Integer, U>): Array<U>
items.map.with_index { |item, index| block.call(item, index) }
end

Type Narrowing

# Type checking with is_a?
def process(value: String | Integer): String
if value.is_a?(String)
value.upcase # T-Ruby knows value is String
else
value.to_s # T-Ruby knows value is Integer
end
end

# Nil checking
def get_length(text: String | nil): Integer
if text.nil?
0
else
text.length # T-Ruby knows text is String
end
end

# Multiple checks
def describe(value: String | Integer | Boolean): String
if value.is_a?(String)
"String: #{value}"
elsif value.is_a?(Integer)
"Number: #{value}"
else
"Boolean: #{value}"
end
end

Literal Types

# String literals
type Status = "pending" | "active" | "completed"
status: Status = "active"

# Number literals
type Port = 80 | 443 | 8080
port: Port = 443

# Symbol literals
type Role = :admin | :editor | :viewer
role: Role = :admin

# Boolean literals
type Yes = true
type No = false

Advanced Types

# Intersection types
type Serializable = Printable & Comparable
obj: Serializable # Must implement both interfaces

# Conditional types (planned)
type NonNullable<T> = T extends nil ? never : T

# Mapped types (planned)
type Readonly<T> = { readonly [K in keyof T]: T[K] }

# Utility types
type Partial<T> # All properties optional
type Required<T> # All properties required
type Pick<T, K> # Select properties
type Omit<T, K> # Remove properties

Type Assertions

# Type casting (use with caution)
value = get_value() as String
number = parse("42") as Integer

# Safe type conversion
def to_integer(value: String | Integer): Integer
if value.is_a?(Integer)
value
else
value.to_i
end
end

Module Type Annotations

module Formatter
# Module method with types
def self.format(value: String, width: Integer): String
value.ljust(width)
end

# Module constants with types
DEFAULT_WIDTH: Integer = 80
DEFAULT_CHAR: String = " "
end

# Mixin module
module Timestamped
@created_at: Integer
@updated_at: Integer

def timestamp: Integer
@created_at
end
end

Common Patterns

Optional Parameters with Defaults

def create_user(
name: String,
email: String,
age: Integer = 18,
active: Boolean = true
): User
User.new(name, email, age, active)
end

Result Type Pattern

type Result<T, E> = { success: Boolean, value: T | nil, error: E | nil }

def divide(a: Float, b: Float): Result<Float, String>
if b == 0
{ success: false, value: nil, error: "Division by zero" }
else
{ success: true, value: a / b, error: nil }
end
end

Builder Pattern

class QueryBuilder
@conditions: Array<String>

def initialize: void
@conditions = []
end

def where(condition: String): self
@conditions << condition
self
end

def build: String
@conditions.join(" AND ")
end
end

Type Guards

def is_string(value: Any): value is String
value.is_a?(String)
end

def is_user(value: Any): value is User
value.is_a?(User)
end

# Usage
value = get_value()
if is_string(value)
puts value.upcase # value is String here
end

Quick Tips

  1. Use type inference - Don't annotate everything, let T-Ruby infer simple types
  2. Prefer union types over Any - String | Integer is better than Any
  3. Use type aliases - Make complex types readable with aliases
  4. Check types before use - Use is_a? and nil? for union types
  5. Leverage generics - Write reusable, type-safe code
  6. Start gradually - You don't need to type everything at once
  7. Use void for side effects - Methods that don't return meaningful values
  8. Avoid over-typing - If the type is obvious, let T-Ruby infer it

Common Type Errors

# ❌ Wrong: Assigning wrong type
name: String = 123 # Error: Integer is not String

# ✅ Correct: Use union type
id: String | Integer = 123

# ❌ Wrong: Accessing property without type check
def get_length(value: String | nil): Integer
value.length # Error: value might be nil
end

# ✅ Correct: Check for nil first
def get_length(value: String | nil): Integer
if value.nil?
0
else
value.length
end
end

# ❌ Wrong: Generic without type parameter
box = Box.new("hello") # Error if type can't be inferred

# ✅ Correct: Specify type parameter
box = Box<String>.new("hello")

File Extensions and Compilation

# T-Ruby source files
hello.trb

# Compile to Ruby
trc hello.trb
# Generates: hello.rb

# Generate RBS types
trc --rbs hello.trb
# Generates: hello.rbs

# Watch mode
trc --watch *.trb

# Type check only (no output)
trc --check hello.trb

Further Reading