luau-types について
luau-typesは、Luauの型システムを中心とする作業向けのスキルです。Luauコードの作成やレビューに使われ、型推論、ジェネリクス、ユニオン、テーブル、モジュールAPIを扱います。実行時最適化やRobloxのアーキテクチャは対象外です。
主な機能
- 01ファイルの型チェックモード選択
- 02変数、関数、テーブルの型付け
- 03推論を保つAPI設計
- 04ジェネリクスとユニオンのモデル化
- 05モジュールとメタテーブルの型付け
活用シーン
- 01Luauファイルのstrictモード選択
- 02安定した公開モジュール型の定義
- 03ジェネリクスによる入出力関係の保持
- 04タグ付きユニオンによる状態モデル化
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ luumenlabs/ luau-skills --skill luau-typesインストール後、Claude Code で/luau-typesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/basic-types-and-table-typing.mdgenerics.mdobject-oriented-typing.mdrefinements.mdroblox-types-in-luau.mdtype-functions.mdtype-system-overview.mdunions-and-intersections.md詳細
luau-types
使用するタイミング
タスクの主な内容が Luau の型システムに関する場合に、このスキルを使用します。
--!strict、--!nonstrict、その他のファイルの型チェックモードから選択する。- 変数、関数、テーブル、モジュールの型注釈を追加または修正する。
anyに帰着せず、型推論を維持する API を設計する。- ジェネリック、ユニオン、インターセクション、オプショナル、タグ付きユニオンを使ってデータをモデル化する。
- オブジェクトのようなテーブル、メタテーブルを使ったモジュール、エクスポートするモジュールの公開インターフェースに型を付ける。
- 型関数やその他の高度な型レベルのユーティリティを記述またはレビューする。
- Roblox のクラス、データ型、列挙型、
IsAに関する知識を、静的な型付けの改善にのみ使用する。
タスクの主な内容が次の項目に関する場合は、このスキルを使用しないでください。
- 型付けの問題以外の、Luau の一般的な構文、制御フロー、メタテーブル、標準ライブラリの使用方法。
- ランタイムのパフォーマンス、プロファイリング、実行頻度の高い箇所の最適化、メモリ割り当ての方針。
- Roblox のネットワーク通信、レプリケーション、データストレージ、クラウド API、ゲームプレイのアーキテクチャ。
判断ルール
- 主な質問が「この型はどうあるべきか?」または「このコードの型チェックを長期的にどう維持すべきか?」である場合、このスキルを使用します。
- タスクが移行中のコードやレガシーコードを明示的に対象としていない限り、新規コードまたは積極的に保守されているコードでは
--!strictを推奨します。 - 推論された形状が正確で読みやすいまま保たれる場合は、注釈を多用する設計よりも、型推論を維持する設計を優先します。
- 利用側で安定した契約を共有する必要がある場合は、モジュールの境界で明示的にエクスポートするエイリアスを優先します。
- 入力と出力の関係が重要な場合はジェネリックを使用し、その関係を
anyに置き換えないでください。 - 値が複数の構造化されたケースのいずれかになり得る場合は、タグ付きユニオンと型の絞り込みを使用します。
- タスクが純粋な言語構文の話に移った場合は、
luau-coreに引き継ぎます。 - タスクが最適化やランタイムコストのトレードオフの話に移った場合は、
luau-performanceに引き継ぎます。 - タスクに型名や型の絞り込みを超えた Roblox ランタイムのアーキテクチャが必要な場合は、適切な
roblox/*スキルを使用します。 - 判断に迷った場合は、型付けの正確性、保守性、またはアナライザーの動作の改善に直接必要のない内容を除外します。
指示
- まず、ファイルモードの要件を特定します。
- 強力な推論と早期のエラー検出には
--!strictを使用します。 - 未解決の値がノイズになる移行中のコードには
--!nonstrictを使用します。 - 分析の無効化がタスクで明示的に求められている場合に限り、
--!nocheckを使用します。
- 強力な推論と早期のエラー検出には
- あらゆる箇所に注釈を追加する前に、有用な推論を維持します。意図を明確にする場合、モジュールの契約を安定させる場合、
selfを制約する場合、または望ましくないanyへの型の拡大を防ぐ場合に注釈を追加します。 - 共有する形状には、具体的なエイリアスを優先します。
- 構造化データにはレコードを使用します。
- 辞書にはインデクサーを使用します。
- 配列には
{T}を使用します。 - モジュール間で使う契約には、エクスポートされたエイリアスを使用します。
- オプショナル型、ユニオン型、インターセクション型を意図的に使います。
T | nilにはT?を使用します。- 状態機械や結果のような値にはタグ付きユニオンを使用します。
- 互換性のあるテーブル機能や関数シグネチャの組み合わせにはインターセクションを使用します。
::によるキャストは、回避策ではなく精度を高める手段として扱います。過度に汎用的な推論を絞り込むために使用し、無関係な型のエラーを隠すためには使用しません。- ジェネリックは、型同士の関係を表すように設計します。
- 変換処理を通じて要素型を維持します。
- コンテナーを通じてキーと値の関係を維持します。
- 型パラメーターで意図を表現できる場合に、
anyを既定にしないようにします。
- Luau の解析方法に応じてテーブルをモデル化します。
- 非シールテーブルには、ローカルでフィールドを追加できます。
- 注釈付きのテーブルや返されるテーブルはシールされます。
- シールされたレコードには幅部分型付けが適用されます。
- オブジェクトのようなモジュールでは、インスタンスデータとクラスの振る舞いを分離し、
setmetatableからインスタンス型を導出します。また、メソッドで共有のクラス型が必要な場合は、selfに明示的な注釈を付けます。 - モジュールの API サーフェスを型安全に保ちます。
- 利用側に公開するデータには、名前付きエイリアスをエクスポートします。
- 実装の詳細は内部に留めます。
- 呼び出し側の型を適切に推論できるシグネチャを選びます。
- Roblox の型知識は、
Instance、Part、Enum.Material、データ型、IsAによる絞り込みなど、注釈と型の絞り込みにのみ使用します。
参照資料の使用
- ファイルモード、構造的型付け、注釈、キャスト、モジュール境界に関するガイダンスについては、
references/type-system-overview.mdを開いてください。 - 組み込み型、
anyやunknownなどの特殊な型、関数シグネチャ、テーブルの状態、インデクサーについては、references/basic-types-and-table-typing.mdを開いてください。 - ジェネリックエイリアス、ジェネリック関数、エイリアスの既定値、推論を維持するコンテナーパターンについては、
references/generics.mdを開いてください。 - 結果の形状、タグ付きユニオン、識別子、安全なインターセクションの使用については、
references/unions-and-intersections.mdを開いてください。 - 真偽値によるチェック、
type(...)ガード、等価性による絞り込み、複合条件、assertによる絞り込みについては、references/refinements.mdを開いてください。 - メタテーブルを使ったクラスの型付け、
selfの注釈、コンストラクターの戻り値の型、エクスポートされたインスタンスエイリアスについては、references/object-oriented-typing.mdを開いてください。 - 解析時の型計算、利用可能なライブラリ、高度な型レベル変換が妥当な場合については、
references/type-functions.mdを開いてください。 - Roblox のクラス、データ型、列挙型、コンストラクター、サービス、
IsAの型付け動作については、references/roblox-types-in-luau.mdを開いてください。 - 依頼内容が明らかにスキルの範囲をまたぐ場合を除き、ほかのスキル参照資料は開かないでください。
チェックリスト
- 選択した型チェックモードが、ファイルの保守目的に合っています。
- 再利用が重要な箇所では、公開モジュールの契約が明示されています。
- 型推論の精度が保たれる場合は、型推論を活用しています。
- 意図的に型チェックを無効にする場合を除き、
anyは避けています。 - テーブルは、実際の形状とシールの挙動に応じて型付けされています。
- ユニオン、交差型、オプショナル型は、曖昧な包括型ではなく、実際の状態を反映しています。
- ジェネリックパラメーターは、呼び出し側が利用する入力と出力の関係を表しています。
- Luau がクラス全体で共有される型を安全に推論できない場合、メソッドの
selfの型が明示されています。 - Roblox の型は、型付けの改善に役立つ場合にのみ使用し、無関係な Roblox のアーキテクチャに踏み込んでいません。
- 一般的な構文のチュートリアル、パフォーマンスに関する助言、ネットワーク/データ/クラウドに関するガイダンスは含まれていません。
よくある間違い
--!nonstrictで変数に型注釈を付けず、意図せずanyにしてしまう。- 役立つジェネリックな関係を、
anyや広すぎるユニオンに置き換えてしまう。 - 型注釈でテーブルを早くシールしすぎた後に、フィールドを追加しようとする。
:を使ったメソッド定義によって、クラス全体で精度の高いself型が自動的に共有されると考える。- 根本的な型設計を修正せず、無関係な型変換を強制するために
::を使う。 - 判別子のないユニオンを作り、その後の型の絞り込みを難しくする。
string & numberのような、互換性のないプリミティブ型の交差型を使う。- 型だけを扱うタスクに、実行時の Roblox アーキテクチャに関するガイダンスを混在させる。
例
安定したモジュールの契約をエクスポートする
--!strict
export type User = {
id: number,
name: string,
nickname: string?,
}
local M = {}
function M.makeUser(id: number, name: string): User
return {
id = id,
name = name,
nickname = nil,
}
end
return M
ジェネリック関数で関係性を維持する
--!strict
local function first<T>(items: {T}): T?
return items[1]
end
local a = first({1, 2, 3}) -- number?
local b = first({"x", "y"}) -- string?
タグ付きユニオンを絞り込む
--!strict
type Loading = { kind: "loading" }
type Ready<T> = { kind: "ready", value: T }
type Failed = { kind: "failed", message: string }
type State<T> = Loading | Ready<T> | Failed
local function readValue(state: State<number>): number?
if state.kind == "ready" then
return state.value
end
return nil
end
明示的な self を持つオブジェクト風モジュールに型を付ける
--!strict
local Counter = {}
Counter.__index = Counter
type CounterData = {
value: number,
}
export type Counter = typeof(setmetatable({} :: CounterData, Counter))
function Counter.new(initialValue: number): Counter
return setmetatable({
value = initialValue,
}, Counter)
end
function Counter.increment(self: Counter, amount: number): number
self.value += amount
return self.value
end
return Counter
コメント
Markdown 対応