Teal – A statically-typed dialect of Lua
175 comments
·May 16, 2025pansa2
creatonez
It's interesting that you mention Typescript. In Typescript's early history, they added a bunch of features that they either thought would make it nicer for C# devs (classes, enums, option chaining, decorators, namespaces, etc.). Eventually, a bunch of these features were added to Javascript natively in nearly the exact same way they were implemented in Typescript. Now, the only remaining non-type-related features not added to Javascript are enums and namespaces, which will never be added because they're poorly designed. Even the Typescript type syntax (but with ignored semantics) may get added to Javascript under a WIP proposal. Some of these features were perhaps mistakes -- private in TS and private in JS will never be able to mean the same thing, and `class` syntax is iffy -- but overall there was an improvement.
By ambitiously adding useful features, could Teal push the upstream to make progress? Probably not because Lua's scope is intended to be small (and we're no longer in the same context as 2015 era Typescript and tc39), but it's interesting to think about.
koito17
Minor nitpick: decorators are still in "stage 3". Not formally part of ECMAScript standard yet.[1]
Anyway, that has not stopped large parts of the JavaScript ecosystem -- notably Angular -- from using an experimental variant of decorators, such as the one provided by TypeScript. [2]
chamomeal
I feel conflicted about decorators, which I’ve only used in the context of nestjs.
They’re undeniably productive, but they’re very black box-ish. Just slap a decorator on a method, now it’s a cron job! Slap a decorator on, and now you’re logging the function call!
I feel like a lot of problems that decorators solve could also be solved with good ol’ higher order functions. Decorators also give zero (or limited? Idk) information to the typescript compiler, so you end up asserting a lot of types instead of inferring them.
I have all these gripes, but it really is amazing to throw decorators on stuff and have it work. Especially with third party libraries that provide decorators. I gave a nestjs app a queueing system by installing bullmq, then just slapping the bullmq decorators around!
Makes me think of the Rich Hickey “simple made easy” talk. Decorators are definitely not simple, which makes me naturally dislike them. But damn are they easy!!
WorldMaker
Even worse a lot of Angular ecosystem still relies a lot on a previous Decorators proposal that was withdrawn at Stage 1. If you are still using the `experimentalDecorators` flag in your build you aren't using the Stage 3 version of Decorators (which don't have a build flag, just a target requirement).
VoidWhisperer
Enums are possibly going to end up in JS eventually - this proposal[0] is at stage 1 (i know the readme says stage 0, it looks like there is a PR to update this). Granted, that means 'under consideration' but it is a start
SoylentOrange
Just a small note about mypy and python - annotations are first-class citizens in Python3 and are not tied to any particular type checking system such as mypy, but are instead a core part of the language and actually serve vital functions in frameworks and libraries that are used to check interfaces such as Pydantic and FastAPI (eg URL params).
Mypy is just one type checker for Python, but there are many others including pyright. In fact pyright is quickly becoming the dominant checker over mypy.
pansa2
Am I right in thinking that Python's type annotation syntax originally came from Mypy though?
IIRC Mypy started off as a type annotation syntax and corresponding type checker for Python. Mypy's type annotations were adopted by Python itself (in version 3.5 - PEP 484), which reduced Mypy's role to be just a type checker.
Since then, type annotations have indeed become a core part of Python - not only are they used in frameworks and libraries, but are also required to use language features like @dataclass.
thristian
No, Python's current type annotation syntax was added in Python 3.0 as a generic annotation syntax, in the hope that somebody else might come along and build a type-checker or other tooling on top:
https://peps.python.org/pep-3107/
MyPy was one such tool, and I think it had conventions for adding type annotations in comments, in places where Python didn't yet support them (such as variable assignment), but I'm pretty sure it was never a TypeScript-style pre-processor - type-annotated programs always ran directly in the unmodified CPython interpreter.
lifthrasiir
That was a major concern when I was using Lua at work. Pretty much every type checker in Lua required transpiling, which doesn't work for many environments (e.g. Redis script). My Kailua [1] was designed that in mind but didn't reach its full potential.
90s_dev
> Teal replaces Lua's tables - the language's signature single, highly-flexible data structure - with separate arrays, tuples, maps, records and interfaces
They're all just Lua tables with specialized type checking for specific behavior.
I really wish the Lua authors would add official types to Lua. The time has come.
pansa2
> I really wish the Lua authors would add official types to Lua.
Never going to happen IMO. Adding static types would change the nature of the language completely, even more than it has in Python.
As Teal shows, it would require giving up one of Lua's core features: tables as the language's single data structure. It would significantly complicate a language known for its simplicity.
Even the implementation would need to change radically - adding a type checker would invalidate the current approach of using a single-pass source-to-bytecode compiler.
dottrap
>> I really wish the Lua authors would add official types to Lua.
> Never going to happen IMO. Adding static types would change the nature of the language completely, even more than it has in Python.
You both are kind of right.
The Lua authors have been working on the new companion language to Lua named Pallene. Pallene is a subset of Lua that adds types, not for the sake of types themselves, but for the purpose of performance. The Pallene compiler can generate optimized native code that potentially removes the need to manually write a module for Lua in C.
The other cool trick is that Pallene and Lua are completely interoperable with each other, so Pallene can be added to existing Lua projects, and you can opt to use regular Lua for the dynamic parts of your code where compilers won't be able to optimize much and strong types might be more trouble than help.
Here is a talk Roberto Ierusalimschy gave about Pallene. https://www.youtube.com/watch?v=pGF2UFG7n6Y
lifthrasiir
In reality, tables are used in specific fashions and not fully generally. (Partly because Lua itself even recognizes some of these fashions and provides relevant operations accordingly.) Lua tables are not really a single data structure; it is a single type that acts as multiple data structures at once.
tiffanyh
> As Teal shows, [official typed Lua] would require giving up one of Lua's core features: tables as the language's single data structure.
Is that true ... you can't have typed tables without giving up tables as a data structure?
wyldfire
> Perhaps it's more similar to TypeScript?
Funny you should mention that:
> It aims to fill a niche similar to that of TypeScript in the JavaScript world, but adhering to Lua's spirit of minimalism, portability and embeddability.
Benjamin_Dobell
You can get pretty far by bolting annotations onto Lua (no compilation step), for example using my IDE:
https://github.com/Benjamin-Dobell/IntelliJ-Luanalysis
Admittedly, I've been focused on some other things recently, but still with some focus on type safety e.g. https://breaka.club/blog/godots-most-powerful-scripting-lang...
ufo
I'm not sure if I follow.
Teal still compiles all those things into plain Lua tables, it's just that the type system has different table subtypes for better type checking. I think the variable scoping is also the same as regular Lua?
TulliusCicero
> Perhaps it's more similar to TypeScript?
I mean that's exactly what the page says, doesn't it?
> It aims to fill a niche similar to that of TypeScript in the JavaScript world, but adhering to Lua's spirit of minimalism, portability and embeddability.
0xFEE1DEAD
Years ago, I tried lua and wasn't impressed. Then I started using Neovim, did the necessary configuration in lua, but continued writing my own scripts in vimscript. Later I started using wezterm and decided to give lua a second shot, and I began to really like it.
I realized my initial dislike for lua stemmed from my experience with javascript (back in the jwquery days), where maintaining large codebases felt like navigating a minefield. The lack of type system made it all too easy to introduce bugs.
But lua isn't like that. It's not weakly typed like javascript - it's more akin to pythons dynamic duck typing system. Its simplicity makes it remarkably easy to write clean maintainable code. Type checking with type is straightforward compared to python, mostly because there are only five basic types (technically seven but I've never used userdata or thread). And I even started to enjoy using metatables once I understood how and when to apply them.
That being said, lua's lack of popularity probably stems from its limited stdlib, which often feels incomplete, and the absence of a robust package manager. luarocks is a pain to work with.
All that being said, I don't really see the point of using this project.
While I do wish type annotations were a native feature, the ones provided by the lsp are good enough for me.
augusto-moura
BTW, you might want to check Lux [1], it's a new approach for Lua packaging. They launched it recently, so there's a lot of work going on. But it looks and feels very promising
0xFEE1DEAD
Oh wow I didn't know someone was actually working on an alternative. It really does look promising. Thank you, definitely going to try it.
lr1970
> That being said, lua's lack of popularity probably stems from its limited stdlib, which often feels incomplete, and the absence of a robust package manager. luarocks is a pain to work with.
And indexing arrays starting from 1 rather than 0.
pull_my_finger
It doesn't "index arrays from 1", it doesn't have arrays, but tables, that can operate as "sequences". It's all documented in the docs.
>>> A table with exactly one border is called a sequence. For instance, the table {10, 20, 30, 40, 50} is a sequence, as it has only one border (5). The table {10, 20, 30, nil, 50} has two borders (3 and 5), and therefore it is not a sequence. (The nil at index 4 is called a hole.) The table {nil, 20, 30, nil, nil, 60, nil} has three borders (0, 3, and 6) and three holes (at indices 1, 4, and 5), so it is not a sequence, too. The table {} is a sequence with border 0. Note that non-natural keys do not interfere with whether a table is a sequence
fanf2
Strings are indexed from 1 as well, which can be pretty annoying. When I was splitting strings into even-sized pieces it was annoying that I kept having to work with odd numbers.
giraffe_lady
> Its simplicity makes it remarkably easy to write clean maintainable code.
Not based on my experience with even just medium-sized lua codebases. Anything over a few thousand lines and in continuous development has been a mess. Not lua's fault per se¹ but the only thing in my experience that compares is what you'd see in pre-laravel php. Every significant codebase is a messy ad hoc one-off framework in its own right.
A lot of people, as always when it comes up, are speaking of their recreational, small-project or config system lua code. Which is fine, it's good for that. But I have a lot of professional experience working in live production lua codebases and my experiences with it are different over there.
¹ A lot of large lua projects started as someone's first lua project or maybe even first code project at all, which is a tremendous accomplishment for a language but not a smooth ride for maintainers taking over those projects.
90s_dev
> But lua isn't like that. It's not weakly typed like javascript - it's more akin to pythons dynamic duck typing system
What? No, Lua's type system is practically identical to JavaScript's.
Even metatables are extraordinarily similar to prototype chains via __index (though much more powerful since they allow for operator overloading, which I wish JS had).
unscaled
I've had a similar journey to you — I've gotten familiar with Lua through using embedded Lua in apps like Neovim, Hammerspoon, Sbarlua and Wezterm. But unfortunately I feel the exact opposite: the more I use Lua, the more I hate it.
Lua doesn't have as many warts as languages like JavaScript or PHP do. The worst offenders are probably the 1-indexing (more of an stdlib issue than a language issue) and variables being global by default (same as JavaScript). It's a minimalist language and I guess this is one of the reason it is so popular as embedded language. But that's exactly why I find myself preferring even (modern) JavaScript to Lua. Lua is so barebones it's just too painful to use for anyone who got used to programming in other languages.
> That being said, lua's lack of popularity probably stems from its limited stdlib, which often feels incomplete, and the absence of a robust package manager. luarocks is a pain to work with.
And that's the crux of it. I guess many people are fine with writing tons of WET code using a barebones library and a bunch of copy-pasted code files thrown around when it comes to their personal scripts. That's all fine, but my brain isn't wired that way and I just feel excruciating pain every time I realize I have to write Lua again.
Luarocks is painful to use, but the main problem is that every embedded Lua you use deals with packages differently. Lua 5.1, 5.2, 5.3, 5.4 and LuaJIT are all incompatible with each other, since every version has breaking changes. Additionally, due to the lack of a standard library, many lua packages have to rely on native code, which makes portability and compatibility even worse. It all means that Lua doesn't really have a package ecosystem.
> But lua isn't like that. It's not weakly typed like JavaScript - it's more akin to pythons dynamic duck typing
I don't understand how Lua is less weakly typed than Java. Both of these languages have dynamic typing and do not support any type annotations or type inference in their core dialects, and both languages have "duck typing".
Where I feel JavaScript is vastly superior to Lua is tooling. JavaScript linters and language servers are far more advanced than Lua language servers, to the point where they can detect a lot of errors that I would waste hours on debugging with Lua. Due to Lua's atrociously bad error messages, without writing a lot of error handling code and copious printf statements, it would be quite hard to find where you've even made a typo in a variable name once your code gets large enough.
So yeah, I get why for some people Lua can be fun, because it's conceptually minimalist, but in practice I hate it with passion.
pmarreck
I've been diving into Lua (a little late to this party, but turns out it's a perfect language to rewrite some commandline scripts I had that were getting unwieldy in Bash, especially with LLM assistance!) and it's really something of an eye-opener.
LuaJITted Lua code runs at 80% (on average, sometimes faster!) of the compiled C version of the same algorithm, typically. Lua is embedded in a surprisingly massive number of products: https://en.wikipedia.org/wiki/List_of_applications_using_Lua The startup time of a script is in nanoseconds. An "echo" written in Lua runs faster than the native echo implementation.
The only warts so far are 1-based indexing (you get used to it), and the fact that LuaJIT is stuck at Lua 5.1 while Lua itself is up to 5.3 or 5.4 and has added some niceties... with Lua proper running slower. And no real standard library to speak of (although some would argue that's a feature; there are a few options and different flavors out there if that's what you need, though- Such as functional-flavored ones...)
Anyway, there's nothing else like it out there. Especially with its relative simplicity.
There are also some neat languages that compile to (transpile to?) Lua, and deserve more attention, such as YueScript https://yuescript.org/, which is a still actively-updated enhanced dialect of MoonScript https://moonscript.org/ (described as "Coffeescript for Lua", although it hasn't been updated in 10 years) although neither of these are typed. HOWEVER... there IS this: TypescriptToLua https://typescripttolua.github.io/, which takes advantage of ALL the existing TypeScript tooling, it just outputs Lua instead of JS!
Rochus
> LuaJITted Lua code runs at 80% (on average, sometimes faster!) of the compiled C version of the same algorithm, typically
Cannot confirm this. It might be true on selected micro benchmarks. Here are the results of the Are-we-fast-yet benchmark suite, which includes a decent set of benchmarks challenging CPU, cache and memory access: https://github.com/rochus-keller/Oberon/blob/master/testcase....
On average, the C and C++ implementations are five times faster than LuaJIT.
> There are also some neat languages that compile to (transpile to?) Lua
Here is a comprehensive list: https://github.com/hengestone/lua-languages. Lanuages like Oberon or Luon directly compile to LuaJIT bytecode (i.e. not to Lua).
Symmetry
The code in Are-we-fast-yet has been heavily optimized. It might still be true that naive LuaJIT can run almost as fast as Naive C.
Rochus
Have a look at the results and the code; there are benchmarks in the suite where the (ideomatic) C/C++ implementation is "only" twice as fast as the corresponding (idiomatic) Lua implementation, but on average (geomean of all factors) it's about five times as fast. The guidelines of the benchmark are pretty strict to enable fair comparisons (see https://github.com/smarr/are-we-fast-yet/blob/master/docs/gu...).
jwatte
Another one of the biggest uses of Lua outside the hyperscaler-type software like nginx or redis: Roblox. Soooo many kids run games on Roblox every day!
Roblox not only runs entirely on Lua, but they've been working on their own type inference version of Lua named Luau, and open sourced it, and it's still in very active development.
const_cast
> but turns out it's a perfect language to rewrite some commandline scripts I had that were getting unwieldy in Bash
IMO this is the perfect use case for Perl. I mean, it's why Perl was invented, but to this day it remains incredibly good at doing this specific task. It's incredibly easy to write and can be very easy to read, and it's much more robust than bash. But best of all - and the reason I think Perl still has a place in the modern world - it's available on practically every computer on Earth. And it will all work. It's so backwards-compatible that 25 year old scripts will run just fine. It's so portable that nothing even comes close. Also, it's shockingly fast. Faster than you would think. Regex is really powerful and it's been the template for so many regex implementations, but definitely be careful of runaway time complexity.
Anyway, Lua is great too. Really nice for embedding into applications ala VBA. Great for config.
pmarreck
Good point about Perl. Why don't I consider Perl? I don't know.
const_cast
Don’t worry, nobody considers Perl
kanbankaren
It is true that LuaJIT is stuck at 5.1, but you could write any performance critical sections in C/C++ and call it from Lua.
Lack of LuaJIT for 5.1+ isn't that big of a deal for desktop apps. The embedded world is still stuck in 5.1, but for them, the benefits of the latest Lua is marginal.
johnisgood
And despite it being stuck at 5.1, it still implements features from other versions. For example, there is the "LJ_52" macro, so you can compile "table.pack" and "table.unpack" into LuaJIT, which I do, because I use both at times.
As someone else have pointed it out, they are cherry picked: https://luajit.org/extensions.html.
hisham_hm
There is also the compat53 library which polyfills most of the missing parts. The Teal compiler has --gen-target and --gen-compat flags which adapts the generated Lua code for different Lua versions, and allows using the compat53 library behind the scenes if desired, so you can get a mostly Lua-5.3+ experience over LuaJIT using Teal.
vrighter
and if you use luajit ffi, those calls actually get called just as fast as from a c program
jiehong
Any recommendations going from bash to lua to watch out for except indexing?
pmarreck
I haven’t found many downsides yet. I was already starting to rewrite some things in Awk (which I was drawn to for similar reasons- fast script startup time, simple easy language with good defaults), but Awk (while still also awesome) isn’t really designed for stuff beyond a certain size (no signal handling unless you use a fork, for example)
LuaJIT is missing bignums, ints that aren’t floats, bit operations, and native utf8 handling, but it can pretty easily be extended with libraries, ffi and metatabling. (I actually made a working bignum library that integrates with gmp, but it has a memory leak somewhere and it’s a rabbit hole/bikeshedding project at this point…)
LLM assistance helps hugely and I really like YueScript’s syntax additions. You can point any LLM at a syntax describing webpage and it will pretty much write that language for you…
nmz
For bignums, have you tried this?
https://web.tecgraf.puc-rio.br/~lhf/ftp/lua/#limath
luajit does have integers (try 5ull+6), bit operations via the bit library (absorbed from lua5.2)
nmz
I do think you're better off using ruby, but if you insist.
Lots of default functionality missing so you MUST have these packages: inspect, luaposix, lrexlib-pcre, lrexlib-posix, lpeg, luastd/stdlib, luasocket, luahttp, luasec, luacheck, penlight
* luajit is unnecessary in almost all cases, you don't need the speed.
* use lsp or luacheck whenever you write something, entr -c luacheck file on everything.
* patterns are not regex which means they do not support lookups, backtracking or |, so you must install lrexlib-pcre or lrexlib-posix (frankly I never need pcre so I stick to lrexlib-gnu or lrexlib-posix).
* overload _ENV so it auto requires unknown things, I have a lua wrapper that does this and it makes it a joy not having all of my scripts with a bunch of require"posix" on all of them
* install inspect to inspect tables
* os.execute and io.popen only accepts strings as parameters which means you should overload it and make a function that accepts tables as well.
* 5.4 is still lacking support for many libraries, 5.3 has most of the libraries.
* assignments default to the global environment so you have to use local keyword or set _ENV to error on assignment (or better yet, don't care, just local _ENV = mymodule)
Overall, Lua is just a mixture of C with a pascal syntax and garbage collection (and also tables which is a weird data structure)
pmarreck
Ruby has a startup time and is slow. (Although compiled Crystal might be an idea...)
I am specifically looking for a language that:
1) is a scripting language (don't have to worry about compiling it)
2) starts up fast (so if I use it in a loop or a sequence of pipes, it won't necessarily be the bottleneck)
3) runs fast
4) is easy to work with and is either ridiculously simple or well-designed (Bash has so many footguns...), and scales up to medium-size code (anything that would take more than 1 file to implement should be promoted to another language)
Awk fit this. So did D, actually. Lua certainly does.
> luajit is unnecessary
Why not use it if it's there, it's faster, and you don't need features beyond 5.1?
> patterns are not regex
They're almost regex, they're faster than regex, and for 90% of use cases, you don't need full regex
> tables which is a weird data structure
Isn't a table basically just a JavaScript object, where metatables are the prototype object? Sort of, at least...
samiv
After having embedded Lua in my game engine and having worked with some Lua games I've come to conclusion that:
- Lua is great from the integrator/engine dev perspective. It's easy to embed and there are several libraries that help with creating bindings between Lua and your game classes.
- Lua has absolutely terrible runtime performance especially when the GC stalls. You soon learn that you have to start moving code to the native side and carefully consider the APIs that you provide for the game so that you can even dream of any type of performance. Haven't tried LuaJIT since that doesn't work with WASM so it's not an option for me.
- The loose runtime typing in Lua is absolutely terrible, and while it's easy and fast to knock up some simple script you really pay the price when you try to maintain or refactor your code and you have no typing information. For the game engine developer this also makes it very hard to provide any kind of help for the game developer, i.e. "intellisense" kind of functionality. I've basically "solved" this by assuming that variables have certain name suffixes and prefixes and when those are present I assume that it has a certain type which lets me provide a list of functions in the script editor to the game developer. Far from perfect. [see link below]
https://github.com/ensisoft/detonator/blob/master/screens/ed...
augusto-moura
The lua language service [1] supports type annotations inside comments [2]. Sure, it is not the same as having types as first class citizens, but I would say that it solves 95% of the editor support and typying problems you mentioned in your 3rd point.
But yeah, PUC-Rio Lua is not fast, but it is acceptable, and maybe one of the most performant of all non-JIT dynamic languages. If you need speed, JIT is a requirement.
Llamamoe
It's a shame you can't use LuaJIT. It's one of if not THE highest performance JIT out there.
spookie
Any alternatives you've tried that are better in those areas?
nicce
What is the usecase for WASM? Browser games?
90s_dev
I'm so relieved to see more types being added to good languages.
So Teal is to Lua as TypeScript is to JavaScript. Which means it automatically plays well with any Lua environment. Unlike luau and nelua which are also statically typed but have their own runtimes.
What version of Lua does it use? Lua gets new versions every few years so I don't know why so many impls don't continuously upgrade to the latest version.
90s_dev
> The core compiler has no dependencies and is implemented as a single tl.lua file which you can load into your projects. Running tl.loader() will add Teal support to your package loader, meaning that require() will be able to run .tl files.
Genius design.
0cf8612b2e1e
Each new Lua version has breaking changes that are of dubious value to keep on the upgrade treadmill. Something like a Python2->3.
LuaJIT is famously on 5.1 with no signs of moving.
bondant
Not moving straight to a more recent version, but still cherry-picking some parts of them. You can see some functionalities from Lua 5.2 and 5.3 are working in Luajit: https://luajit.org/extensions.html
90s_dev
I guess all of this means Lua has "flavors" more than "versions".
RS-232
Lua is a good language. It's like C, if C were a scripting language.
It's got an awesome C API. It's fast, lightweight, and embeddable. It's more performant than Python. It's a staple in video game scripting.
90s_dev
It's nothing like C, and that's so much of its charm.
Semantically, Lua is almost identical to the core of JavaScript. Metatables are a genius alternative to prototype chains.
Lua's syntax is beautifully simple and unambiguous, but at the cost of being moderately inconvenient in 2025 unfortunately. It could benefit from an ESNext-style renewal.
I get why they made the C API that way, but in practice it's very easy to get wrong.
I'm not sure how fast vanilla Lua is today compared to similar languages. I think LuaJIT (and Luau?) are most often used when performance is needed.
isr
FYI, for those who may not be aware, moonscript is the "coffeescript" for lua. It has been in production use for quite a while (the author of moonscript also created itch.io, using ... moonscript).
yuescript, from the dora-ssr game engine dev, is essentially moonscript-2.0
And of course, if you want to treat lua as the scheme-like it really is (deep down), then ... fennel.
Lots of choices. They all compile to straightforward lua, are very easy to incorporate (you can even compile at runtime, if you wish), and all employ full lua semantics, meaning zero runtime overhead
EDIT: and the curse of not reading fully ahead strikes again (doh!). Someone else has made the same points below ...
growlNark
Sure, if you compare via semantics Lua and Javascript make sense to liken. But in terms of complexity, Lua is far more like C. There's no unfucking all the horrible decisions baked into javascript and I wouldn't touch it with a ninety-foot pole, but Lua still has some hope.
nmz
> Lua's syntax is beautifully simple and unambiguous
local print = print
("hello"):format()
local foo = func
("args to func"):itreturnedatable("!")
RonaldK9
I don't think it's a good language, and I hate it. I've made thousands of the same mistakes with it—typing . instead of :. There's a reason Lua has a smaller audience than assembly.
Philpax
> There's a reason Lua has a smaller audience than assembly.
I don't think that's true. It's a very embedded language. Its use in video games and video game modding alone would outnumber the number of people directly writing assembly to achieve things.
hisham_hm
Teal currenly supports generating code for Lua 5.1 and up, including LuaJIT. There are compiler flags --gen-target and --gen-compat which control various specifics of code generation.
ufo
Teal compiles to Lua text files. I believe it's compatible with both Lua 5.1 and 5.4
alanh
Oh, clever name. Typed Lua → TL → "Tee Ell" → Teal
And the extension is .tl
Sharlin
Off-topic comment, but as an ESL speaker I just this week randomly learned that teal the color is named after the duck species Anas crecca, called (edit: common or Eurasian) teal in English.
nozzlegear
TIL! My wife is a photographer and she's been photographing a ton of Blue-winged Teals over the last couple months during their migration. I assumed that the ducks had been named after the color.
Sharlin
Cool! (Just to be clear, I meant the common, or Eurasian, teal whose iridescent green head markings the color’s apparently named after. The NA teals are closely related, although it seems they were assigned to their own genus in 2009 as it was discovered that the then-Anas was not monophyletic.)
Generally colors are named after things in nature and not the other way around, given that the latter would’be had names for a long time, and most color names are comparatively recent inventions, driven by modern dyes and pigments and status, fashion, etc concerns. A West European peasant in the 11th century would’ve known the bird well, possibly trapped them for food, but would’ve had very little need for a separate word for ”blue-green”.
The history of color words is quite interesting. There’s a specific progression that almost all languages have gone through. It’s fairly well known that many East Asian languages don’t have separate names for ”blue” and ”green” at all (except as modern loans). Accordingly, they don’t usually make the distinction mentally, one could think that they simply consider them hues of ”cyan”.
seafoamteal
I'm one of today's lucky 10_000 apparently! Only learned that just now.
phant0mas
You can also check this talk from Hissam last fosdem https://fosdem.org/2025/schedule/event/fosdem-2025-6147-what...
sundarurfriend
There's a type declaration file for the vim global that's defined by default in Neovim: https://github.com/teal-language/teal-types/blob/master/type...
to be used via `global_env_def` described in https://teal-language.org/book/declaration_files.html
And though they mention it as being for third party libraries, this also seems a way to declare types for your own code in an external file, thus keeping your code as runnable Lua and benefiting from type checking too. That seems like a neat workflow for developing Neovim plugins with this: instead of having to constantly regenerate Lua from .tl files so Neovim can pick up your changes during development.
Edit: or maybe https://github.com/teal-language/tl#loading-teal-code-from-l... this is the easier way to do it. `require` and use `loader` during development, generate the Lua once things are somewhat stable.
andreypopp
> this also seems a way to declare types for your own code in an external file, thus keeping your code as runnable Lua and benefiting from type checking too
The declaration file isn't used to typecheck the code the declaration is for. It is only for consumers of the code.
sundarurfriend
Ah that's a shame. I was hoping it would work via sidecar files like Ruby's RBS [1] or Python's stub files [2]
I was editing my comment during your reply, and added this:
> or maybe https://github.com/teal-language/tl#loading-teal-code-from-l... this is the easier way to do it. `require` and use `loader` during development, generate the Lua once things are somewhat stable.
Does that sound like the right idea then?
[1] https://github.com/ruby/rbs [2] https://mypy.readthedocs.io/en/stable/stubs.html
HexDecOctBin
Has anyone used this? Any reviews? Based on the Github issues, the type system seems to have some holes in it, but it's not obvious how bad is it in real world.
hombre_fatal
I used it to write a couple Pico-8 games a year or two ago since Lua + dynamic typing is a major obstacle for me managing game code over time. Teal worked well for that.
andre-la
I'm using it for my game
wslh
There is another TEAL (uppercase) programming language: <https://developer.algorand.org/docs/get-details/dapps/avm/te...>
brianolson
I designed and named the Transaction Execution Approval Language for the Algorand blockchain in 2020. I'm partial to the original, but as it grew it got rebranded to be the "Algorand Virtual Machine". Glad someone still remembers it as TEAL!
tkzed49
I vote we give the name to the lua one!
90s_dev
Seconded.
ayrtondesozzla
I think you and GP both mean that this TEAL is adjacent to crptocurrency, and therefore, who cares about stepping on toes?
This heuristic works well in most cases maybe, but will lead to false positives sometimes. May I gently suggest that this might be one of those cases. Algorand is the project of this fellow
https://en.m.wikipedia.org/wiki/Silvio_Micali
Credentials aren't faultless but they do provide a certain web of trust. If you browse the academic and professional history of this fellow, I think you'll agree.
Algorand is, I think, as serious and sincere a research project as any other.
ufo
Do you know how old that is? Lua Teal has already been around for at least 5 years.
xlii
I really want to like Lua but I just can’t. Tried Lua/Fennel/even Teal but I just can’t.
I can’t tell what it is exactly. Maybe those weird global rules? Maybe inspection of objects and metatables? Maybe the weird mix of verbose and not verbose (e.g. getting output of a process requiring popen and manual handling but then function can take more arguments than declared and whateva) or exotic control flow and structures (metatable, global env).
It’s interesting language, but I just grit my teeth every time I’m interacting with it.
null
max0563
This is super cool. I have been using TypeScript To Lua (https://github.com/TypeScriptToLua/TypeScriptToLua) for a little game side project and it works quite well, I am pleased with it. It does end up generating a lot of Lua code though because it has to support all of TypeScript’s features, which isn’t ideal. I’d expect Teal’s output to be much more concise Lua which has me interested.
hisham_hm
Teal's output is currently pretty much 1-to-1 with the input apart from removing all of the type information of course. (I've been trying hard to keep it that way so that the error messages in stack traces match the input lines without having to do source mapping.)
> Teal is a statically-typed dialect of Lua.
I was expecting Teal to be "Lua + type annotations", similar to Mypy. However from a quick look it does indeed seem to be a "dialect" in its own right. Teal is Lua-like and compiles to Lua, but there's more to it than just static types. Perhaps it's more similar to TypeScript?
For example, Teal replaces Lua's tables - the language's signature single, highly-flexible data structure - with separate arrays, tuples, maps, records and interfaces. It changes the variable scoping rules and even adds macro expressions.
Teal therefore seems substantially more complex than Lua. The author recognizes this in the conclusion to a recent presentation [0]: Lua is "small and simple", maybe Teal is "something else"? Lua is for "scripting", maybe Teal is better suited to "applications/libraries"?
[0] https://youtu.be/Uq_8bckDxaU?t=1618