世界を動かす技術を、日本語で。

ティール - Luaの静的型付けダイアレクト

概要

  • Teal はLuaの静的型付き方言で、TypeScriptのような役割を担う。
  • 型アノテーションやジェネリクスなど、 拡張機能 をLuaに提供することが特徴。
  • tlコンパイラ で.tlファイルを.luaに変換することが可能。
  • インストールや開発支援ツール も充実している。
  • MITライセンス でオープンソースとして公開されている。

Tealとは何か

  • TealLua の静的型付き方言であることを明示すること
  • 型アノテーション による配列、マップ、レコード、インターフェース、ユニオン型、ジェネリクスの指定が可能であることを強調すること
  • TypeScript がJavaScriptに与える役割と同様のニッチをLuaで担うことを目指すこと
  • Luaのミニマリズム・移植性・組み込みやすさ を維持することを重視すること
  • tlコンパイラ により.tlソースコードから.luaファイルへの変換を実現すること

Tealのコード例

  • Tealコード は型アノテーションが明示的に記述できることを示すこと
  • 例:
    • local function add(a: number, b: number): number 形式で関数の引数と戻り値の型を指定すること
    • return a + b end で型安全な計算を実行すること
    • local s = add(1, 2) で型推論が働くこと
    • print(s) で結果を出力すること

Tealの体験・プレイグラウンド

  • Teal Playground を利用し、ブラウザ上でTealコンパイラを試すことが可能であること
  • このページのソースコードを参考にすることもできること
  • オンラインで Tealコード を編集・実行できることを確認すること

Tealのインストール方法

  • LuaRocks を使用してluarocks install tlコマンドでインストールすること
  • Linux・Windows用のバイナリ も提供されていること
  • 大規模プロジェクトでは Cyan ビルドツールの利用を推奨すること
  • Visual Studio Code 統合用のvscode-tealNeoVim 用のteal-language-serverなどの拡張機能が存在すること
  • 他にも各種エディタ・ツール連携が進んでいること

ドキュメント・学習資料

  • Teal公式ドキュメント をオンラインで参照できること
  • Luaと型システムの歴史やTealの動機・進捗に関する 講演動画 が複数公開されていること
    • Minimalism versus types (2019)
    • Minimalistic typed Lua is here (2020)
    • What's next for Teal (2021)
    • Five years of Teal: minimalism versus growth in language design (2024)
    • What should Teal be? - musings on FOSS project directions (2025)

コミュニティ・開発体制

  • GitHub 上で開発や議論が活発に行われていること
  • GitHubフォーラムMatrixチャット (#teal-language_community:gitter.im)でコミュニティ交流が可能であること
  • Hisham Muhammad がプロジェクトを開始し、貢献者が増加中であること
  • Teal自身の実装もTealで書かれている という特徴があること

ライセンス

  • MITライセンス で公開されており、Luaと同じ自由度を持つこと
  • オープンソースプロジェクト として自由に利用・改変・配布できること

Hackerたちの意見

別のTEAL(大文字)のプログラミング言語があるよ: https://developer.algorand.org/docs/get-details/dapps/avm/te...>

luaの方にその名前をあげようって投票するよ!

それがどれくらい古いか知ってる?Lua Tealはもう少なくとも5年は存在してるよ。

2020年にAlgorandブロックチェーンのためにトランザクション実行承認言語を設計して名付けたんだ。元のものには愛着があるけど、成長するにつれて「Algorandバーチャルマシン」にリブランドされたんだ。まだTEALとして覚えてくれてる人がいて嬉しいよ!

いい言語に新しい型が追加されるのを見ると、すごくホッとする。TealはLuaに対して、TypeScriptはJavaScriptに対するみたいなもんだね。つまり、Lua環境と自動的にうまく連携するってこと。luauやneluaは静的型付けだけど、それぞれ独自のランタイムがあるから違うんだ。Luaのどのバージョンを使ってるの?Luaは数年ごとに新しいバージョンが出るから、なんでそんなに多くの実装が最新バージョンにアップグレードしないのか分からない。

コアコンパイラには依存関係がなく、プロジェクトに読み込める単一のtl.luaファイルとして実装されてる。tl.loader()を実行すると、パッケージローダーにTealサポートが追加されて、require()で.tlファイルが実行できるようになる。天才的な設計だね。

Luaはいい言語だよ。Cがスクリプト言語だったらこんな感じ。素晴らしいC APIがあるし、速くて軽量で埋め込み可能。Pythonよりもパフォーマンスがいいし、ゲームスクリプトでは定番だね。

新しいLuaのバージョンには、アップグレードを続ける価値が疑わしい破壊的変更があるんだよね。Python2から3に移行するみたいな感じ。LuaJITは5.1に固執していて、全然動く気配がないし。

TealはLuaのテキストファイルにコンパイルされるよ。Lua 5.1と5.4の両方に対応してると思う。

Tealは現在、Lua 5.1以降のコード生成をサポートしていて、LuaJITも含まれてるよ。コード生成のさまざまな詳細を制御するコンパイラフラグ --gen-target と --gen-compat があるよ。

お、賢い名前だね。Typed Lua → TL → "Tee Ell" → Teal そして拡張子は.tl

トピックとは関係ないコメントだけど、ESLの話者として、今週偶然にtealという色がアナス・クレッカというカモの種類にちなんで名付けられたことを知ったよ(編集: 英語では普通のまたはユーラシアのtealと呼ばれる)。

誰かこれ使ったことある?レビューはある?Githubの問題を見る限り、型システムにいくつか穴があるみたいだけど、実際にはどれくらいひどいのかは分からないね。

1、2年前にPico-8のゲームをいくつか作るのに使ったんだけど、Luaと動的型付けはゲームコードを管理する上で大きな障害だったから、Tealはそれに対してうまく機能したよ。

ゲームに使ってるよ。

最近Luaにハマってるんだけど(ちょっと遅れて参加だけど、コマンドラインスクリプトをBashから書き直すのにぴったりな言語だってわかった!特にLLMの助けもあってね!)、ほんと目からウロコだよ。LuaJITで動かすLuaコードは、同じアルゴリズムのコンパイルされたCバージョンの平均80%(時にはそれ以上!)で動くんだ。Luaは意外と多くの製品に組み込まれてるよね:https://en.wikipedia.org/wiki/List_of_applications_using_Lua スクリプトの起動時間はナノ秒単位。Luaで書いた「echo」は、ネイティブのecho実装より速く動くんだ。今のところの欠点は1から始まるインデックス(慣れるけどね)と、LuaJITがLua 5.1に縛られてることかな。Lua自体は5.3か5.4まで進んで、いくつかの便利な機能が追加されてるけど、Luaの方が遅いんだよね。それに、特に話すべき標準ライブラリもない(でもそれが特徴だって言う人もいるし、必要ならいくつかのオプションや異なるフレーバーがあるよ、例えば関数型のやつとか…)。とにかく、こんな言語は他にないよ。特にその相対的なシンプルさがいい。Luaにコンパイル(トランスパイル?)する面白い言語もあって、もっと注目されるべきだと思う。例えばYueScript https://yuescript.org/は、MoonScript https://moonscript.org/の強化された方言で、今も活発に更新されてるんだ(「LuaのためのCoffeescript」と言われてるけど、10年更新されてない)。どちらも型付けはされてないけどね。とはいえ…これがあるんだ:TypescriptToLua https://typescripttolua.github.io/。これはすべての既存のTypeScriptツールを活用して、JSの代わりにLuaを出力するんだよ!

確かにLuaJITは5.1に縛られてるけど、パフォーマンスが重要な部分はC/C++で書いてLuaから呼び出せばいいんだ。5.1以上のLuaJITがないのはデスクトップアプリにはそれほど大きな問題じゃないよ。組み込みの世界はまだ5.1に留まってるけど、彼らにとって最新のLuaの利点は微々たるものだね。

bashからluaに移行する際に、インデックス以外で気をつけるべきことはある?

LuaJITでコンパイルされたLuaコードは、同じアルゴリズムのコンパイルされたCバージョンの平均80%(時にはそれ以上!)の速度で動く、というのは確認できないな。特定のマイクロベンチマークではそうかもしれないけど。CPU、キャッシュ、メモリアクセスに挑戦する良いベンチマークセットを含むAre-we-fast-yetベンチマークスイートの結果はこちらだよ: https://github.com/rochus-keller/Oberon/blob/master/testcase.... 平均して、CとC++の実装はLuaJITの5倍速いよ。 > Luaにコンパイル(トランスパイル?)する面白い言語もいくつかあるよ。こちらが包括的なリスト: https://github.com/hengestone/lua-languages。OberonやLuonのような言語はLuaJITのバイトコードに直接コンパイルされる(つまりLuaにはならない)。

Luaのもう一つの大きな使い道は、nginxやredisのようなハイパースケーラータイプのソフトウェアの外で、Robloxだね。毎日めちゃくちゃ多くの子供たちがRobloxでゲームをしてるよ!Robloxは完全にLuaで動いてるだけじゃなくて、Luauっていう独自の型推論バージョンのLuaを開発してオープンソースにして、今もすごく活発に開発中なんだ。https://github.com/luau-lang/luau

TealはLuaの静的型付け方言なんだ。Tealは「Lua + 型アノテーション」みたいなものだと思ってたけど、ざっと見た感じ、確かに独自の「方言」って感じだね。TealはLuaに似ててLuaにコンパイルされるけど、静的型だけじゃないみたい。TypeScriptにもっと似てるのかな?例えば、TealはLuaのテーブル - 言語の特徴的な単一で非常に柔軟なデータ構造 - を、別々の配列、タプル、マップ、レコード、インターフェースに置き換えてる。変数のスコープルールも変わるし、マクロ式も追加される。だからTealはLuaよりもかなり複雑に見えるね。著者も最近のプレゼンテーションの結論でこれを認めてるよ[0]:Luaは「小さくてシンプル」、もしかしたらTealは「別の何か」なのかも?Luaは「スクリプト用」、Tealは「アプリケーション/ライブラリ」に向いてるのかもね?[0] https://youtu.be/Uq_8bckDxaU?t=1618

Luaにアノテーションを追加するだけでかなりのところまで行けるよ(コンパイルステップなし)、例えば僕のIDEを使ってね:https://github.com/Benjamin-Dobell/IntelliJ-Luanalysis 正直、最近は他のことに集中してたけど、型安全にも少しは注目してるよ。例えば:https://breaka.club/blog/godots-most-powerful-scripting-lang...

それは僕が仕事でLuaを使ってたときの大きな懸念だったよ。Luaのほとんどの型チェッカーはトランスパイルが必要で、多くの環境では機能しない(例えばRedisスクリプト)。僕のKailua [1]はそのことを考えて設計されたけど、完全なポテンシャルには達しなかったんだ。[1] https://github.com/devcat-studio/kailua/

もしかしたらTypeScriptにもっと似てるのかな?それを言うなら面白いね:> JavaScriptの世界でTypeScriptと似たニッチを埋めることを目指してるけど、Luaのミニマリズム、ポータビリティ、埋め込みやすさの精神を守ってるんだ。

TealはLuaのテーブル - 言語の特徴的な単一で非常に柔軟なデータ構造 - を、別々の配列、タプル、マップ、レコード、インターフェースに置き換えてる。実際には、特定の動作のために特化した型チェックがあるLuaテーブルに過ぎないんだ。Luaの著者が公式な型をLuaに追加してくれることを本当に願ってる。そろそろその時が来たと思う。

mypyとPythonについての小さなメモだけど、アノテーションはPython3ではファーストクラスの市民で、mypyのような特定の型チェックシステムに結びついてるわけじゃなくて、言語のコアな部分であり、PydanticやFastAPIのようなインターフェースをチェックするために使われるフレームワークやライブラリで重要な機能を果たしてるんだ(例えばURLパラメータ)。mypyはPython用の型チェッカーの一つに過ぎないけど、pyrightを含む他にもたくさんあるよ。実際、pyrightはmypyを超えて急速に支配的なチェッカーになりつつあるんだ。

Typescriptの話をするのは面白いね。Typescriptの初期には、C#の開発者にとって便利だと思われる機能(クラス、列挙型、オプションチェイニング、デコレーター、名前空間など)がたくさん追加されたんだ。結局、これらの機能の多くが、ほぼ同じ方法でJavascriptにネイティブに追加された。今、Javascriptに追加されていないタイプに関係ない機能は列挙型と名前空間だけで、これはデザインが悪いから絶対に追加されないだろうね。Typescriptの型構文(ただし意味は無視されるかもしれない)は、WIP提案の下でJavascriptに追加されるかもしれない。これらの機能のいくつかは、たぶん間違いだったかもしれないけど(TSのprivateとJSのprivateは同じ意味には絶対にならないし、class構文も微妙だし)、全体的には改善があったと思う。Tealが有用な機能を積極的に追加することで、上流を進展させることができるかな?たぶん無理だろうね、Luaのスコープは小さくすることが意図されているし(2015年のTypescriptやtc39の文脈とはもう違うし)、考えるのは面白いけど。

ちょっとよくわからないな。Tealは結局、全部を普通のLuaテーブルにコンパイルするだけで、型システムがより良い型チェックのために異なるテーブルのサブタイプを持ってるだけだと思う。変数のスコープも普通のLuaと同じじゃない?

もしかしてTypeScriptにもっと似てるのかな?だって、ページにそう書いてあるじゃん? > JavaScriptの世界でTypeScriptと似たニッチを埋めることを目指してるけど、Luaのミニマリズム、ポータビリティ、埋め込みやすさの精神を守ってるんだって。

それから、Hissamの去年のFOSDEMでのトークもチェックしてみてね。https://fosdem.org/2025/schedule/event/fosdem-2025-6147-what...

Neovimでデフォルトで定義されているvimのグローバル用の型宣言ファイルがあるよ: https://github.com/teal-language/teal-types/blob/master/type... これは、https://teal-language.org/book/declaration_files.html に書かれているglobal_env_defを通じて使えるんだ。彼らはこれをサードパーティライブラリ用だと言っているけど、自分のコードの型を外部ファイルで宣言する方法としても使えるみたいで、そうすることでコードを実行可能なLuaのままに保ちつつ、型チェックの恩恵も受けられるんだ。これを使ってNeovimプラグインを開発するのは面白いワークフローだね:.tlファイルからLuaを常に再生成する必要がなくなるから、Neovimが開発中に変更を拾えるようになる。編集:もしかしたら、https://github.com/teal-language/tl#loading-teal-code-from-l... これが簡単な方法かも。開発中はrequireしてloaderを使って、物事がある程度安定したらLuaを生成する感じで。

自分のコードの型を外部ファイルで宣言する方法としても使えるみたいで、そうすることでコードを実行可能なLuaのままに保ちつつ、型チェックの恩恵も受けられるんだ。宣言ファイルは、宣言されているコードの型チェックには使われないよ。これはコードの消費者のためだけのものなんだ。

数年前にluaを試してみたけど、あんまり感心しなかったんだ。その後、Neovimを使い始めて、luaで必要な設定をしたけど、自分のスクリプトはvimscriptで書き続けた。後にweztermを使い始めて、luaをもう一度試してみることにしたら、すごく好きになったんだ。最初のluaに対する嫌悪感は、javascript(jwqueryの時代)での経験から来ていたことに気づいた。大きなコードベースを維持するのは地雷原を歩くような感じだったからね。型システムがないと、バグを導入するのが簡単すぎた。でもluaはそうじゃない。javascriptのように弱い型付けではなくて、pythonの動的ダックタイピングシステムに近いんだ。そのシンプルさのおかげで、クリーンでメンテナブルなコードを書くのが驚くほど簡単になる。型チェックはpythonに比べて簡単で、基本的な型は5つだけ(技術的には7つだけど、userdataやthreadは使ったことがない)だからね。メタテーブルの使い方と適用するタイミングを理解したら、それを使うのも楽しめるようになった。ただ、luaの人気がないのは、限られた標準ライブラリが不完全に感じることや、堅牢なパッケージマネージャーがないからだと思う。luarocksは扱いづらいし。とはいえ、このプロジェクトを使う意味はあまり感じないな。型アノテーションがネイティブ機能だったらいいのにと思うけど、lspが提供するものでも十分だよ。

ところで、Lux [1]をチェックしてみるといいよ。Luaのパッケージングに対する新しいアプローチなんだ。最近始まったばかりだから、いろいろ進行中みたい。でも、すごく期待できそうだよ! [1]: https://github.com/nvim-neorocks/lux

でも、Luaはそんな感じじゃないよ。JavaScriptみたいに弱い型付けじゃなくて、Pythonのダックタイピングシステムに近いんじゃない? え?違うよ、Luaの型システムはほぼJavaScriptと同じだよ。メタテーブルも__indexを介したプロトタイプチェーンにすごく似てるし(オペレーターのオーバーロードができるから、JSにもあったらいいのにね)。

そのシンプルさが、クリーンでメンテナブルなコードを書くのを驚くほど簡単にする。中規模のLuaコードベースでもそうは思えないけど。数千行を超えて継続的に開発しているものは、いつも混乱してる。Luaのせいじゃないけど¹、私の経験では、事前LaravelのPHPで見られるようなものと同じだ。重要なコードベースは、どれも混乱したアドホックな一回限りのフレームワークになってる。いつもそうだけど、多くの人が自分のレクリエーションや小規模プロジェクト、設定システムのLuaコードを語ってる。まあ、それはそれでいいんだけど。だけど、私は本番環境のLuaコードベースでのプロの経験がたくさんあって、そっちでは全然違う経験をしてる。¹ 多くの大規模Luaプロジェクトは、誰かの最初のLuaプロジェクト、あるいは初めてのコードプロジェクトとして始まったもので、言語にとっては素晴らしい成果だけど、そういうプロジェクトを引き継ぐメンテナにとってはスムーズな道のりではない。

そうは言っても、Luaの人気がないのは、限られた標準ライブラリのせいで、しばしば不完全に感じることや、しっかりしたパッケージマネージャーがないからだと思う。luarocksは使いづらいし、配列のインデックスが0じゃなくて1から始まるのもね。

あなたと似たような道を歩んできたよ。NeovimやHammerspoon、Sbarlua、Weztermみたいなアプリで埋め込まれたLuaを使って、Luaに慣れ親しんできた。でも残念ながら、正反対の気持ちだ。Luaを使えば使うほど、嫌いになっていく。LuaにはJavaScriptやPHPのような厄介な部分は少ないけど、一番の問題は1から始まるインデックス(これは言語の問題というより標準ライブラリの問題)と、変数がデフォルトでグローバルになること(JavaScriptと同じ)。ミニマリストな言語だから、埋め込み言語として人気がある理由の一つだと思う。でもだからこそ、(現代の)JavaScriptの方が好ましく感じる。Luaは本当に基本的すぎて、他の言語でプログラミングに慣れた人には使うのが辛すぎる。そうは言っても、Luaの人気がないのは、限られた標準ライブラリのせいで、しばしば不完全に感じることや、しっかりしたパッケージマネージャーがないからだと思う。luarocksは使いづらいし、これが問題の核心だと思う。多くの人は、個人のスクリプトに関しては、基本的なライブラリとコピー&ペーストしたコードファイルを使って、たくさんのWETコードを書くことに満足しているんだろうね。それはそれでいいけど、私の脳はそういう風にはできていなくて、Luaを書くたびに苦痛を感じる。luarocksは使いづらいけど、主な問題は、使う埋め込みLuaがパッケージを扱う方法がそれぞれ違うこと。Lua 5.1、5.2、5.3、5.4、LuaJITはすべて互換性がないし、各バージョンには破壊的な変更がある。さらに、標準ライブラリがないため、多くのLuaパッケージはネイティブコードに依存しなければならず、ポータビリティや互換性がさらに悪化している。つまり、Luaには本当にパッケージエコシステムがないってことだ。だけどLuaはそんなことないよ。JavaScriptのように弱い型付けではなく、Pythonの動的ダックタイピングに近いと思う。LuaがJavaよりも弱い型付けじゃないのは理解できない。どちらの言語も動的型付けで、コアの方言では型注釈や型推論をサポートしていないし、どちらの言語も「ダックタイピング」を持っている。JavaScriptがLuaよりも圧倒的に優れているのはツールだと思う。JavaScriptのリンターや言語サーバーは、Luaの言語サーバーよりもずっと進んでいて、Luaでデバッグに何時間もかかるようなエラーを多く検出できる。Luaのひどいエラーメッセージのせいで、たくさんのエラーハンドリングコードやprintf文を書かないと、コードが大きくなったときに変数名のタイプミスを見つけるのはかなり難しい。だから、Luaが概念的にはミニマリストで楽しいと感じる人がいるのは理解できるけど、実際には情熱を持って嫌いだ。

ゲームエンジンにLuaを埋め込んで、いくつかのLuaゲームで作業してきた結果、以下の結論に至ったよ: - Luaは統合者やエンジン開発者の視点から見ると素晴らしい。埋め込みが簡単で、Luaとゲームクラスのバインディングを作るのに役立つライブラリもいくつかある。 - Luaは特にGCがストールするとランタイムパフォーマンスがひどい。パフォーマンスを考えるなら、コードをネイティブ側に移動させ始める必要があるってすぐにわかる。LuaJITはWASMで動かないから試してないけど、私には選択肢じゃない。 - Luaの緩いランタイム型付けは本当にひどくて、簡単なスクリプトを書くのは楽だけど、コードを維持したりリファクタリングしようとすると、型情報がないから大変なことになる。ゲームエンジン開発者にとっても、ゲーム開発者に対して「インテリセンス」的な機能を提供するのが難しい。私は変数に特定の名前の接尾辞や接頭辞があると仮定して、それがあるときは特定の型を持っていると考えて、スクリプトエディタでゲーム開発者に関数のリストを提供できるようにしてる。完璧とは言えないけどね。[下のリンク参照] https://github.com/ensisoft/detonator/blob/master/screens/ed...

その分野で試した他の代替品はある?

Lua言語サービス [1] はコメント内で型注釈をサポートしてるよ [2]。確かに、型が第一級市民じゃないけど、あなたが3番目のポイントで言ったエディタサポートや型付けの問題の95%を解決してると思う。でも、PUC-Rio Luaは速くはないけど、許容範囲内で、非JITの動的言語の中では最もパフォーマンスが良いかもしれない。スピードが必要なら、JITは必須だね。[1]: https://luals.github.io/ [2]: https://luals.github.io/wiki/annotations/

LuaJITが使えないのは残念だね。あれは最高のパフォーマンスを誇るJITの一つだよ。

WASMの使い道って何?ブラウザゲームとか?