Examples Verified (100%)
型エイリアス
型エイリアスを使用すると、型にカスタム名を作成でき、コードをより読みやすく保守しやすくします。型のニックネームと考えてください—新しい型を作成するのではなく、複雑な型をより扱いやすく理解しやすくします。
なぜ型エイリアスか?
型エイリアスはいくつかの重要な目的を果たします:
- 可読性の向上 - 複雑な型表現を意味のある名前で置換
- 繰り返しの削減 - 一度定義し、どこでも使用
- 意図の文書化 - 名前が型が表すものを伝えることができる
- リファクタリングの簡略化 - 一箇所で型を変更
型エイリアスなしで
# 複雑な型がすべての場所で繰り返される
def find_user(id: Integer): Hash<Symbol, String | Integer | Boolean> | nil
# ...
end
def update_user(id: Integer, data: Hash<Symbol, String | Integer | Boolean>): Boolean
# ...
end
def create_user(data: Hash<Symbol, String | Integer | Boolean>): Integer
# ...
end
# これが何を表すか理解しにくい
users: Array<Hash<Symbol, String | Integer | Boolean>> = []
型エイリアス使用
# 一度定義
type UserData = Hash<Symbol, String | Integer | Boolean>
# どこでも使用 - はるかに明確!
def find_user(id: Integer): UserData | nil
# ...
end
def update_user(id: Integer, data: UserData): Boolean
# ...
end
def create_user(data: UserData): Integer
# ...
end
# これが何を表すか明確
users: Array<UserData> = []
基本的な型エイリアス
型エイリアスを作成する構文はシンプルです:
type AliasName = ExistingType
シンプルなエイリアス
# プリミティブ型のエイリアス
type UserId = Integer
type EmailAddress = String
type Price = Float
# エイリアスの使用
user_id: UserId = 123
email: EmailAddress = "alice@example.com"
product_price: Price = 29.99
# エイリアスを使用する関数
def send_email(to: EmailAddress, subject: String, body: String): Boolean
# ...
end
def calculate_discount(original: Price, percentage: Float): Price
original * (1.0 - percentage / 100.0)
end
ユニオン型エイリアス
ユニオン型はエイリアスから大きな恩恵を受けます:
# 以前:繰り返されるユニオン型
def process(value: String | Integer | Float): String
# ...
end
def format(value: String | Integer | Float): String
# ...
end
# 以後:明確なエイリアス
type Primitive = String | Integer | Float
def process(value: Primitive): String
# ...
end
def format(value: Primitive): String
# ...
end
# さらなる例
type ID = Integer | String
type JSONValue = String | Integer | Float | Boolean | nil
type Result = :success | :error | :pending
コレクションエイリアス
複雑なコレクション型をより読みやすくします:
# 配列エイリアス
type StringList = Array<String>
type NumberList = Array<Integer>
type UserList = Array<User>
# ハッシュエイリアス
type StringMap = Hash<String, String>
type Configuration = Hash<Symbol, String | Integer>
type Cache = Hash<String, Any>
# ネストしたコレクション
type Matrix = Array<Array<Integer>>
type TagMap = Hash<String, Array<String>>
type UsersByAge = Hash<Integer, Array<User>>
# コレクションエイリアスの使用
users: UserList = []
config: Configuration = {
port: 3000,
host: "localhost",
debug: true
}
tags: TagMap = {
"ruby" => ["language", "dynamic"],
"rails" => ["framework", "web"]
}
ジェネリック型エイリアス
型エイリアス自体がジェネリックになり、型パラメータを受け取ることができます:
基本的なジェネリックエイリアス
# ジェネリックResult型
type Result<T> = T | nil
# 使用法
user_result: Result<User> = find_user(123)
count_result: Result<Integer> = count_records()
# ジェネリックコールバック型
type Callback<T> = Proc<T, void>
# 使用法
on_user_load: Callback<User> = ->(user: User): void { puts user.name }
on_count: Callback<Integer> = ->(count: Integer): void { puts count }
# ジェネリックペア型
type Pair<A, B> = Array<A | B> # 例のために簡略化
# 使用法
name_age: Pair<String, Integer> = ["Alice", 30]
複雑なジェネリックエイリアス
# メタデータ付きジェネリックコレクション
type Collection<T> = Hash<Symbol, T | Integer | String>
# 使用法
user_collection: Collection<User> = {
data: User.new("Alice"),
count: 1,
status: "active"
}
# ジェネリック変換関数型
type Transformer<T, U> = Proc<T, U>
# 使用法
to_string: Transformer<Integer, String> = ->(n: Integer): String { n.to_s }
to_length: Transformer<String, Integer> = ->(s: String): Integer { s.length }
# ジェネリックバリデータ型
type Validator<T> = Proc<T, Boolean>
# 使用法
positive_validator: Validator<Integer> = ->(n: Integer): Boolean { n > 0 }
email_validator: Validator<String> = ->(s: String): Boolean { s.include?("@") }
部分適用ジェネリックエイリアス
一部の型パラメータを固定し、他を開いたままにしたエイリアスを作成できます:
# 基本ジェネリック型
type Response<T, E> = { success: Boolean, data: T | nil, error: E | nil }
# 部分適用 - エラー型を固定
type APIResponse<T> = Response<T, String>
# 使用法
user_response: APIResponse<User> = {
success: true,
data: User.new("Alice"),
error: nil
}
product_response: APIResponse<Product> = {
success: false,
data: nil,
error: "Product not found"
}
# 別の例
type StringMap<V> = Hash<String, V>
# 使用法
string_to_int: StringMap<Integer> = { "one" => 1, "two" => 2 }
string_to_user: StringMap<User> = { "admin" => User.new("Admin") }
実用的な型エイリアス
ドメイン固有の型
# Eコマースドメイン
type ProductId = Integer
type OrderId = String
type CustomerId = Integer
type Price = Float
type Quantity = Integer
type Product = Hash<Symbol, ProductId | String | Price>
type OrderItem = Hash<Symbol, ProductId | Quantity | Price>
type Order = Hash<Symbol, OrderId | CustomerId | Array<OrderItem> | String>
# ドメイン型の使用
def create_order(customer_id: CustomerId, items: Array<OrderItem>): Order
{
id: generate_order_id(),
customer_id: customer_id,
items: items,
status: "pending"
}
end
def calculate_total(items: Array<OrderItem>): Price
items.reduce(0.0) { |sum, item| sum + item[:price] * item[:quantity] }
end
ステータスと状態型
# アプリケーションステータス
type Status = :pending | :processing | :completed | :failed
type UserRole = :admin | :editor | :viewer
type Environment = :development | :staging | :production
# HTTP関連型
type HTTPMethod = :get | :post | :put | :patch | :delete
type HTTPStatus = Integer # より具体的にできる: 200 | 404 | 500 など
type Headers = Hash<String, String>
# 状態型の使用
class Request
@method: HTTPMethod
@path: String
@headers: Headers
@status: Status
def initialize(method: HTTPMethod, path: String): void
@method = method
@path = path
@headers = {}
@status = :pending
end
def add_header(key: String, value: String): void
@headers[key] = value
end
def status: Status
@status
end
end
JSONとAPI型
# JSON型
type JSONPrimitive = String | Integer | Float | Boolean | nil
type JSONArray = Array<JSONValue>
type JSONObject = Hash<String, JSONValue>
type JSONValue = JSONPrimitive | JSONArray | JSONObject
# APIレスポンス型
type APIError = Hash<Symbol, String | Integer>
type APISuccess<T> = Hash<Symbol, Boolean | T>
type APIResult<T> = APISuccess<T> | APIError
# JSON型の使用
def parse_config(json: String): JSONObject
# JSON文字列をオブジェクトにパース
JSON.parse(json)
end
def api_call<T>(endpoint: String): APIResult<T>
begin
data = fetch(endpoint)
{ success: true, data: data }
rescue => e
{ success: false, error: e.message, code: 500 }
end
end
関数型
# 一般的な関数シグネチャ
type Predicate<T> = Proc<T, Boolean>
type Mapper<T, U> = Proc<T, U>
type Consumer<T> = Proc<T, void>
type Supplier<T> = Proc<T>
type Comparator<T> = Proc<T, T, Integer>
# 関数型の使用
def filter<T>(array: Array<T>, predicate: Predicate<T>): Array<T>
array.select { |item| predicate.call(item) }
end
def map<T, U>(array: Array<T>, mapper: Mapper<T, U>): Array<U>
array.map { |item| mapper.call(item) }
end
def for_each<T>(array: Array<T>, consumer: Consumer<T>): void
array.each { |item| consumer.call(item) }
end
# 使用法
numbers = [1, 2, 3, 4, 5]
is_even: Predicate<Integer> = ->(n: Integer): Boolean { n.even? }
evens = filter(numbers, is_even) # [2, 4]
to_string: Mapper<Integer, String> = ->(n: Integer): String { n.to_s }
strings = map(numbers, to_string) # ["1", "2", "3", "4", "5"]
print_it: Consumer<Integer> = ->(n: Integer): void { puts n }
for_each(numbers, print_it)
型エイリアスの構成
より単純なエイリアスから複雑な型エイリアスを構築できます:
# 基本型
type UserId = Integer
type Username = String
type Email = String
type Timestamp = Integer
# 構成された型
type UserIdentifier = UserId | Username | Email
type UserMetadata = Hash<Symbol, String | Timestamp>
type UserData = Hash<Symbol, UserIdentifier | String | Timestamp>
# 部分から構成された完全なユーザー型
type User = {
id: UserId,
username: Username,
email: Email,
metadata: UserMetadata
}
# 別の例:複雑さの増加
type Coordinate = Float
type Point = Array<Coordinate> # [x, y]
type Line = Array<Point> # [point1, point2]
type Polygon = Array<Point> # [point1, point2, point3, ...]
type Shape = Point | Line | Polygon
type DrawingLayer = Array<Shape>
type Drawing = Hash<String, DrawingLayer>
再帰型エイリアス
準備中
この機能は将来のリリースで計画されています。
将来、T-Rubyはツリー構造と連結リストのための再帰型エイリアスをサポートする予定です:
# ツリー構造
type TreeNode<T> = {
value: T,
children: Array<TreeNode<T>>
}
# 連結リスト
type ListNode<T> = {
value: T,
next: ListNode<T> | nil
}
# JSON(完全再帰)
type JSONValue =
| String
| Integer
| Float
| Boolean
| nil
| Array<JSONValue>
| Hash<String, JSONValue>
ベストプラクティス
1. 説明的な名前を使用
# 良い:明確で説明的な名前
type EmailAddress = String
type ProductPrice = Float
type UserRole = :admin | :editor | :viewer
# あまり良くない:不明確な省略
type EA = String
type PP = Float
type UR = :admin | :editor | :viewer
2. 関連するエイリアスをグループ化
# 良い:ドメインごとに整理
# ユーザー関連型
type UserId = Integer
type Username = String
type UserEmail = String
type UserData = Hash<Symbol, String | Integer>
# 製品関連型
type ProductId = Integer
type ProductName = String
type ProductPrice = Float
type ProductData = Hash<Symbol, String | Integer | Float>
3. 複雑な型にエイリアスを使用
# 良い:複数回使用される複雑な型にエイリアス
type QueryResult = Hash<Symbol, Array<Hash<String, String | Integer>> | Integer>
def execute_query(sql: String): QueryResult
# ...
end
def cache_result(key: String, result: QueryResult): void
# ...
end
# あまり良くない:複雑な型の繰り返し
def execute_query(sql: String): Hash<Symbol, Array<Hash<String, String | Integer>> | Integer>
# ...
end
4. シンプルな型に過度なエイリアスを使わない
# 不要:Stringはすでに明確
type S = String
type N = Integer
# 良い:意味を追加する場合のみエイリアス
type EmailAddress = String # 意味的な意味を追加
type UserId = Integer # 目的を明確化
型エイリアス vs クラス
型エイリアスは新しい型を作成しません—代替名にすぎません。これはクラスとは異なります:
# 型エイリアス - 単なる名前
type UserId = Integer
# 両方とも同じ型
id1: UserId = 123
id2: Integer = 456
id1 = id2 # OK - 同じ型
# クラス - 新しい型を作成
class UserIdClass
@value: Integer
def initialize(value: Integer): void
@value = value
end
end
# 異なる型
user_id: UserIdClass = UserIdClass.new(123)
int_id: Integer = 456
# user_id = int_id # エラー:異なる型!
それぞれをいつ使うか
# 型エイリアスを使用:
# - 意味的な明確性が必要だが同じ基本的な動作を望む場合
# - 複雑な型表現を簡略化したい場合
type EmailAddress = String
type JSONData = Hash<String, Any>
# クラスを使用:
# - 異なる動作を持つ別個の型が必要な場合
# - カプセル化とメソッドが必要な場合
# - ランタイム型チェックが必要な場合
class Email
@address: String
def initialize(address: String): void
raise "Invalid email" unless address.include?("@")
@address = address
end
def domain: String
@address.split("@").last
end
end
一般的なパターン
オプショナル型
# オプショナル/ナラブル型エイリアス
type Optional<T> = T | nil
type Nullable<T> = T | nil
# 使用法
user: Optional<User> = find_user(123)
name: Nullable<String> = user&.name
結果型
# 失敗する可能性のある操作のための結果型
type Result<T, E> = { success: Boolean, value: T | nil, error: E | nil }
type SimpleResult<T> = T | Error
# 使用法
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
ビルダー型
# 設定ビルダー
type Config = Hash<Symbol, String | Integer | Boolean>
type ConfigBuilder = Proc<Config, Config>
# 使用法
def configure(&block: ConfigBuilder): Config
config = {
port: 3000,
host: "localhost",
debug: false
}
block.call(config)
end
型エイリアスによる文書化
型エイリアスはインライン文書化の役割を果たします:
# エイリアス名が型が表すものを文書化
type PositiveInteger = Integer # > 0であるべき
type NonEmptyString = String # 空であってはならない
type Percentage = Float # 0.0から100.0であるべき
def calculate_discount(price: Float, discount: Percentage): Float
price * (1.0 - discount / 100.0)
end
def repeat(text: NonEmptyString, times: PositiveInteger): String
text * times
end
次のステップ
型エイリアスを理解したので、次を探索してください: