@tilua/parser 3.1.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,13 +13,12 @@ the same one either way.
13
13
  |---|---|
14
14
  | [`@tilua/compiler`][compiler] | building a project to one Luau file |
15
15
  | [`@tilua/language-server`][server] | editor support over LSP |
16
- | [`@tilua-types/roblox`][roblox], [`@tilua-types/lua`][lua], [`@tilua-types/sunc`][sunc] | the globals a project may use |
16
+ | [`@tilua-types/roblox`][roblox], [`@tilua-types/sunc`][sunc] | the globals a project adds to Lua's |
17
17
  | `@tilua/parser` | this: tokens, AST, scopes, types |
18
18
 
19
19
  [compiler]: https://www.npmjs.com/package/@tilua/compiler
20
20
  [server]: https://www.npmjs.com/package/@tilua/language-server
21
21
  [roblox]: https://www.npmjs.com/package/@tilua-types/roblox
22
- [lua]: https://www.npmjs.com/package/@tilua-types/lua
23
22
  [sunc]: https://www.npmjs.com/package/@tilua-types/sunc
24
23
  [vscode]: https://marketplace.visualstudio.com/search?term=tilua
25
24
 
@@ -75,19 +74,23 @@ Neither analysis mutates the AST; both return side tables.
75
74
 
76
75
  ## Projects
77
76
 
78
- **No globals are built in** — not `print`, not `string`, not `game`. Only the
79
- language's own utility types are (`Partial`, `Pick`, `Omit`, `Record`,
80
- `ReturnType`, `Truthy`, ...; see `PRELUDE_SOURCE`). A project lists the type
81
- libraries it uses in `tilua.config.json`, the way TypeScript uses `@types/*`:
77
+ **Lua's standard library is built in**, as JavaScript's is in TypeScript:
78
+ `print`, `pairs`, `pcall`, `string`, `math`, `table`, `os`, `coroutine` and
79
+ `console` are there in every file with nothing listed (see
80
+ `STANDARD_LIBRARY_SOURCE`), and so are the language's own utility types
81
+ (`Partial`, `Pick`, `Omit`, `Record`, `ReturnType`, `Truthy`, ...; see
82
+ `PRELUDE_SOURCE`). What a host adds — Luau's and Roblox's `game`, `task`,
83
+ `Instance` — a project lists in `tilua.config.json`, the way TypeScript uses
84
+ `@types/*`:
82
85
 
83
86
  ```bash
84
- npm i -D @tilua-types/roblox # Luau + Roblox; or @tilua-types/lua on its own
87
+ npm i -D @tilua-types/roblox # Luau + Roblox
85
88
  ```
86
89
 
87
90
  ```jsonc
88
91
  // tilua.config.json
89
92
  {
90
- "types": ["roblox"], // and what it depends on: @tilua-types/lua
93
+ "types": ["roblox"], // on top of Lua's standard library
91
94
  "paths": { "@shared/*": ["src/shared/*"] }, // import aliases, as in tsconfig
92
95
  "sourceMap": "sourcemap.json" // a Rojo sourcemap, or null
93
96
  }
@@ -103,7 +106,13 @@ npm i -D @tilua-types/roblox # Luau + Roblox; or @tilua-types/lua on its
103
106
  matches every installed type library it fits (`"@tilua-types/*"`), in name
104
107
  order. A relative path (`"./types"`, `"./defs.d.tilua"`) loads the project's
105
108
  own definitions. A type library's own type-library dependencies load first;
106
- one that is not installed is an error.
109
+ one that is not installed is an error. `"lua"` — `@tilua-types/lua`, where
110
+ the standard library used to be — loads nothing: it is already there, and
111
+ a library that still depends on it does not bring it in twice.
112
+ - **`noLib`** — `true` leaves the standard library out, as TypeScript's
113
+ `noLib` does: no `print`, no `string`, only what `types` declares. For a
114
+ host with none of Lua's, or a library of one's own in its place. With it,
115
+ `"lua"` in `types` loads that package as an ordinary library.
107
116
  - **`paths`** — tsconfig rules: an exact pattern wins, then the `*` pattern
108
117
  with the longest prefix; targets resolve from `baseUrl` (default: the
109
118
  config's folder).
@@ -111,6 +120,11 @@ npm i -D @tilua-types/roblox # Luau + Roblox; or @tilua-types/lua on its
111
120
  follow it, and a file the tree maps gets its own `script`, so
112
121
  `script.Parent.Remotes` is typed. A `.tilua` file matches the Luau file of
113
122
  the same path.
123
+ - **`target`** and **`output`** — the compiler's: which Lua to emit for
124
+ (`"luau"`, the default, or `"lua51"`), and how many files to write
125
+ (`"single"`, the default; `"chunks"`, which also writes a file for what only
126
+ an `import()` reaches; or `"modules"`, one file per module). The parser only
127
+ checks them.
114
128
 
115
129
  | function | does |
116
130
  |---|---|
@@ -118,20 +132,38 @@ npm i -D @tilua-types/roblox # Luau + Roblox; or @tilua-types/lua on its
118
132
  | `loadConfig(path, host?)` | read and check one config |
119
133
  | `resolveTypeLibraries(config, host?)` | the `.d.tilua` files to load, in order |
120
134
  | `moduleCandidates(from, specifier, config?)` / `resolveModulePath(...)` | what an `import` means |
135
+ | `importExpressions(program)` | every `import("...")` written in a file |
121
136
  | `sourceMapTypes(text, path, { classes })` | the tree's types, and `scriptFor(file)` |
122
137
 
123
138
  Every problem comes back as `{ file, message, line, column }`, pointing into
124
139
  the config (or sourcemap) it is about. `host` reads files — pass your own to
125
140
  read unsaved editor buffers or to record what was read.
126
141
 
127
- `type` / `typeof` are **not** special-cased in the analyzer either: they are
128
- overload sets in `@tilua-types/lua` and `@tilua-types/roblox`, and narrowing is derived
129
- from them. Without a library that declares them, they narrow nothing.
142
+ `typeof v` is the language's own, an operator like `not` and `#`: it needs no
143
+ library, and Lua's `type()` and Luau's `typeof()` functions are declared by
144
+ none. It answers Luau's names — `"nil"`, `"boolean"`, `"number"`, `"string"`,
145
+ `"function"`, `"thread"`, `"buffer"`, `"userdata"` — except for a table, which
146
+ is an `"array"` or an `"object"`. `typeof v == "array"` narrows `v`, and
147
+ `== "table"` is an error: it is never the answer. There is no `typeof(v)`
148
+ function: written that way it is an error, and a parenthesised operand stands
149
+ apart from the operator — `typeof (a or b)`.
150
+
151
+ What a runtime's own values answer is a library's to say, in one alias:
152
+
153
+ ```ts
154
+ type TypeofNames = { Vector3: Vector3, Instance: Instance }
155
+ ```
156
+
157
+ Each property is the name `typeof` gives a value of the property's type; a
158
+ value several fit (a `Part` is an `Instance`) is the first one's.
159
+ `TypeAnalysis.typeofTables` lists each `typeof v` whose `v` is, by its type,
160
+ an array or an object wherever it is a table — what a compiler need not find
161
+ out as the program runs.
130
162
 
131
163
  Libraries stack: a name declared again *adds* to what an earlier library gave
132
164
  it — overloads of a function accumulate, and the members of a declared table
133
- merge. That is how `@tilua-types/roblox` extends Lua's `table` and `type` without
134
- restating them.
165
+ merge. That is how `@tilua-types/roblox` extends Lua's `table` without
166
+ restating it.
135
167
 
136
168
  ## The language, in brief
137
169
 
@@ -219,6 +251,23 @@ is what a JavaScript arrow is for.
219
251
 
220
252
  **Declarations** — `const` and `let` only; Lua's `local` is gone.
221
253
 
254
+ What a `let` is first given is its type from then on, as in TypeScript:
255
+ `let n = 1` holds numbers, and `n = "a"` is an error. Only a name that starts
256
+ out holding nothing — `let x`, `let x = nil` — takes the type of whatever is
257
+ put in it later. A `let` declared with a type and no value (`let x: number`)
258
+ cannot be read until every way to the read has assigned it — `Variable 'x' is
259
+ used before being assigned` — unless its type admits `nil`. A function
260
+ written in between may read it: it runs later, when it is called.
261
+
262
+ **`n++` and `n--`** are `n += 1` and `n -= 1`: statements, as Luau's compound
263
+ assignments are, so they give no value and cannot be written inside an
264
+ expression. They apply to anything `+=` does — `t.count++`, `xs[i]--` — and
265
+ are checked as it is: the operator has to apply, and what it gives has to fit.
266
+ `--` is also how a comment starts, so `n--` is the decrement only where the
267
+ dashes touch the name (or the `]`) before them and nothing but the end of the
268
+ line, a `;`, a `}` or a comment follows; `n-- note` is still `n` and a
269
+ comment. `++n` is reported, with the spelling tilua uses.
270
+
222
271
  **Functions** — `function name() { ... }` declares `name` in the enclosing
223
272
  scope; like a TypeScript function declaration it cannot be reassigned.
224
273
  `const` and `let` do not apply to functions. `function T.name()` and
@@ -260,16 +309,40 @@ brings in names that are types and nothing else: unlike TypeScript, using one
260
309
  as a value is an error, and only type positions — `typeof A` included — may
261
310
  name it. Compiled code keeps no trace of it.
262
311
 
312
+ `import("./m")` is an expression: the module's exports as one value — what
313
+ `import * as M from "./m"` names `M` — read where the expression runs rather
314
+ than before the file does. The module is loaded the first time anything asks
315
+ for it, and the value comes back at once: there is no promise to wait on. The
316
+ path has to be a string literal, since which module it is must be known when
317
+ the project is built. On a line of its own, `import("./setup")` loads the
318
+ module for what it does. `importExpressions(program)` lists every one in a
319
+ file.
320
+
263
321
  **Methods of strings, arrays and tables** — a value answers to the methods
264
- its metatable's `__index` has, written with `:`:
322
+ its metatable's `__index` has. They are members, as a JavaScript object's
323
+ are: read with `.`, a method is a function whose first parameter is its
324
+ `self`, handed to it as any argument is. `:` hands it over for you, as Lua's
325
+ always has:
265
326
 
266
327
  ```luau
267
- const long = names:filter(n => #n > 3):map(string.upper)
268
- print(names:join(", "), text:trim(), text:upper())
328
+ const long = names:filter(n => n.length > 3):map(n => n:upper())
329
+ print(names.join(names, ", "), text.trim(text), "abc":upper())
269
330
  const point = { x: 1, y: "up" }
270
331
  const [x, y] = point:values() -- [number, string]
332
+ const join = names.join -- (self: string[], separator?: string) => string
271
333
  ```
272
334
 
335
+ `modes.includes(s)` leaves the `self` out, and is reported as that: call it
336
+ with `:`. The other way round, `o:f(x)` on a function that takes no receiver
337
+ would hand it `o` as `x`, and is reported too. `Stack.push(s, 1)`, which
338
+ passes the receiver by hand, is an ordinary call.
339
+
340
+ **`length`** — `xs.length` is how many a list holds and `text.length` a
341
+ string's length: Luau's `#`, which tilua does not have (`#xs` is an error that
342
+ says to write `xs.length`). A tuple's is known: `[number, string]` has length
343
+ `2`. A table with a `length` of its own is that member, and a class that
344
+ declares `__len` answers what `__len` does.
345
+
273
346
  Strings, arrays and tables are the language's own, so their metatables are
274
347
  too: the prelude declares them, in tilua, and they are there with no type
275
348
  library at all. A string's is Lua's (`upper`, `sub`, with one value where Lua
@@ -277,7 +350,12 @@ answers several: `find` is an array) plus the JavaScript-shaped ones (`trim`,
277
350
  `startsWith`, ...); an array's is JavaScript's (`filter`, `map`, `join`, ...),
278
351
  with Lua's indices — the first element is 1, `indexOf` answers `nil` rather
279
352
  than -1 — and `push`, `pop`, `shift`, `unshift`, `sort` and `reverse` change
280
- the array. A table's are `keys`, `values` and `entries`, which answer a tuple
353
+ the array. Looking for a value is not adding one, so `includes` and `indexOf`
354
+ take any value, not only one the array's type already holds — and `includes`
355
+ is a guard: `if (modes:includes(s))` narrows `s` to a mode. `concat` may join
356
+ arrays of other types (`(T | U)[]`). The ones that only read take a read-only
357
+ list too (`readonly T[]`, what `as const` makes), as TypeScript's
358
+ `ReadonlyArray` does; the ones that change it do not. A table's are `keys`, `values` and `entries`, which answer a tuple
281
359
  in the order the table's type wrote its members, not `string[]` as
282
360
  JavaScript's `Object.keys` does; the analyzer supplies that order as
283
361
  `ObjectKeys<T>`, `ObjectValues<T>` and `ObjectEntries<T>`. A member of a
@@ -285,7 +363,7 @@ value's own with the same name is what a call reaches, and a class instance,
285
363
  which has a metatable of its own, has none of them.
286
364
 
287
365
  No Lua array or table really has these methods, so the compiler lowers each
288
- call into its own runtime (`names:filter(f)` becomes `array.filter(names, f)`);
366
+ call into its own runtime (`names.filter(f)` becomes `array.filter(names, f)`);
289
367
  a string's Lua methods stay plain method calls.
290
368
 
291
369
  A library adds to a metatable by declaring the same target again, and a
@@ -340,8 +418,9 @@ such as `print(x)`, and `globalValue` for a global read as a value, such as
340
418
  `local p = print`. A local with the same name belongs to the author, and no
341
419
  hook is asked about it. A runtime can read `__LINES__`, the bundle's line map
342
420
  (`nil` outside a bundle), to turn a line Luau reports back into a place in the
343
- project. `console:log`, `print` and `error` in `@tilua-types/lua` are built on
344
- these hooks.
421
+ project. One that answers with a new array wraps it in `__ARRAY__(...)`, which
422
+ writes it down as an array for `typeof`. The compiler's own lowering of the
423
+ standard library — `console:log`, `error`, `pcall` — is built on these hooks.
345
424
 
346
425
  **A `(` that starts a line** continues the statement above it, as in Lua and
347
426
  in JavaScript — `const v = map[key]` followed by `("A"):upper()` is one
@@ -350,6 +429,53 @@ write `;` before the `(` when a new statement was meant.
350
429
 
351
430
  **Object types** — `{ name: T, name?: T, [K]: V }`, and a name that is not an
352
431
  identifier is quoted, as in the literal: `{ "Respawn After Kill": boolean }`.
432
+ An index signature may name its key as TypeScript does, `[key: string]: V`, and
433
+ its key may be a template literal: `` { [`on${string}`]: Handler } `` takes every
434
+ `onX`, and an object literal with any other key is excess. A string or a list
435
+ fits a shape that names what it answers to: `"abc"` is a `{ length: number }`.
436
+ Members are separated by `,`, `;` or a line break, and may be written the
437
+ other ways TypeScript writes them:
438
+
439
+ ```luau
440
+ type Counter = {
441
+ readonly id: number
442
+ step(by: number): this -- a method: (self: this, by: number) => this
443
+ reset?(): nil -- an optional one
444
+ get total(): number -- read-only, unless a `set` is written too
445
+ set label(value: string)
446
+ (n: number): string -- calling the value; several are overloads
447
+ new (seed: number): Counter -- what its `new` makes: { new: (seed: number) => Counter }
448
+ }
449
+ ```
450
+
451
+ A method is called with `:`, as a class's methods are: its first parameter is
452
+ the receiver, typed `this`, so `counter:step(1)` hands `counter` over and
453
+ `counter.step(1)` is the missing argument it is. A signature with no return
454
+ type returns `nil`. Calling the value and having members too is the functions
455
+ and the members together — Lua builds such a value with a `__call` metatable.
456
+
457
+ **Interfaces** — `interface Name<T> extends A, B<T> { ... }`, with the members
458
+ an object type takes. It is a type alias for the bases and the members
459
+ together, with what TypeScript adds: two interfaces of one name are one, their
460
+ members merged (a method written in each is an overload set), and a member
461
+ that does not fit the one it replaces in a base is reported. `export
462
+ interface` exports it, as `export type` does.
463
+
464
+ ```luau
465
+ interface Named { name: string }
466
+ interface Greeter extends Named {
467
+ greet(other: Named): string
468
+ }
469
+ class Person implements Greeter {
470
+ name = "Ada"
471
+ function greet(other: Named): string { return `hi ${other.name}` }
472
+ }
473
+ ```
474
+
475
+ **`this` in a type** — TypeScript's polymorphic `this`: the value a member is
476
+ read from. A method that returns `this` returns whatever it was called on, so
477
+ `Builder.new():add(1):done()` keeps the subclass's members through the chain.
478
+ Inside the class it is the instance.
353
479
 
354
480
  **Optionality** — there is no `T?` shorthand. `?` in type position always
355
481
  belongs to a conditional type, and in expression position to a ternary or an
@@ -372,6 +498,29 @@ ternary. Parentheses end a chain. A chain cannot be assigned to (`a?.b = 1` is
372
498
  an error). A chain that got through narrows what it tested: inside
373
499
  `if (part?.Parent)`, and `if (part?.Name == "Door")`, `part` is not nil.
374
500
 
501
+ **`??`** — `a ?? b` is `a`, or `b` where `a` is nil; `b` is read only then.
502
+ Unlike `a or b` a `false` stays, which is what a `boolean | nil` wants:
503
+ `settings.enabled ?? true`. As in TypeScript it does not mix with `and` or
504
+ `or` without parentheses.
505
+
506
+ **`in`** — `"key" in t` asks whether `t` holds something at `key`: in Lua a
507
+ key whose value is nil is a key that is not there, so it is `t.key ~= nil`.
508
+ The key is a string or a number and `t` a table. It narrows as TypeScript's
509
+ does: where it holds, `t` is one of the union members that can have `key`, and
510
+ `t.key` is not nil; where it does not, `t` is none of the members that must.
511
+
512
+ **`instanceof`** — `v instanceof Dog` is true when `v` was built by `Dog` or
513
+ by a class extending it. It walks the links every instance has: `v.ClassObject`,
514
+ then each `.ParentClass` up the chain. It narrows `v` to `Dog`, and only a
515
+ class written in tilua can stand on its right — a `declare class` is the
516
+ host's, and Roblox's answer `IsA` instead.
517
+
518
+ **Accessors in an object literal** — `{ get full() { ... }, set full(v) { ...
519
+ } }` reads and writes `full` through functions, with the object as `this`. Lua
520
+ has no such thing, so the object gets a metatable that runs them; a name with a
521
+ getter and no setter is read-only, and assigning it is an error at runtime as
522
+ well as in the types.
523
+
375
524
  **Classes** — types are structural, except for classes. A definitions file
376
525
  declares one with `declare class`, and it is nominal, as Roblox's classes are:
377
526
 
@@ -383,8 +532,8 @@ declare class Part extends BasePart { Shape: EnumItem }
383
532
  A `Part` is a `BasePart` and an `Instance` because it extends them. A
384
533
  `ReplicatedStorage` is not a `Part`, and no table literal is an `Instance`,
385
534
  however alike their members. A class still fits a shape that names members it
386
- has (`{ Name: string }`). It is not a table, though, so `typeof(part)` picks
387
- the `"Instance"` overload, not `"table"`. Members are inherited, and a subclass
535
+ has (`{ Name: string }`). It is not a table, though, so `typeof part` is
536
+ `"Instance"`, as the library's `TypeofNames` says, not `"object"`. Members are inherited, and a subclass
388
537
  may narrow one (`Parent: SomeFolder`).
389
538
 
390
539
  **`class ... { }`** — a class written in code, rather than declared in a
@@ -504,7 +653,7 @@ class Square extends Shape {
504
653
  instances' metatable, so `function __add(other: Vec): Vec` in a class is the
505
654
  `+` of its instances — and the type checker reads it the same way: `a + b`
506
655
  between two `Vec`s is a `Vec`. `__sub`, `__mul`, `__div`, `__idiv`, `__mod`,
507
- `__pow`, `__unm`, `__concat`, `__len` (`#v`), `__eq`, `__lt` and `__le` (`<`,
656
+ `__pow`, `__unm`, `__concat`, `__len` (`v.length`), `__eq`, `__lt` and `__le` (`<`,
508
657
  `>`, `<=`, `>=`), `__call` (calling an instance), `__iter` (`for a, b in v`)
509
658
  and `__tostring` all work this way, and a class extending another inherits
510
659
  them. Each is checked: it takes the operands Luau hands it, returns what Luau
@@ -690,14 +839,24 @@ destructuring instead.
690
839
  ```luau
691
840
  join("-", ...names) -- every name
692
841
  join("-", ...names, "z") -- and one more after them
693
- add3(...nums) -- however many `nums` turns out to hold
842
+ add3(...trio) -- `trio: [number, number, number]`: exactly three
694
843
  const both = [...names, "z"]
695
844
  ```
696
845
 
697
- What the array holds is checked against what it fills. How many it holds is
698
- not known, so nothing is said about the count — unless it is a tuple, which
699
- holds a known value at each position and is checked one by one. Spreading
700
- something that is not a list is reported.
846
+ What the array holds is checked against what it fills. How many an array
847
+ holds is not known, so, as in TypeScript, it can only fill a rest parameter —
848
+ `add3(...nums)` with `nums: number[]` is an error, and so is `h(...nums)` for
849
+ an `h(a: number, ...more: number[])`, whose `a` it would have to fill. A
850
+ tuple holds a known value at each position: it fills exactly that many
851
+ parameters, checked one by one and counted, several tuples together too.
852
+ Spreading something that is not a list is reported, and so is spreading a
853
+ list that may be nil — write `...(xs ?? [])`.
854
+
855
+ In an object literal, `...source` copies what `source` has: over a union, one
856
+ object per member; over a value that may be nil, every member optional; over
857
+ a class instance, its fields — its methods live on the class table, which a
858
+ copy does not reach. A copy is a new table, so nothing in it is read-only.
859
+ `const [first, ...rest] = tuple` leaves `rest` a tuple of what is left.
701
860
 
702
861
  **Branded types** — nothing in the type model is about branding; an
703
862
  intersection already means it. `string & { __brand }` is assignable to
@@ -714,7 +873,7 @@ findUser(id) -- ok
714
873
  findUser("raw") -- '"raw"' is not assignable to 'UserId'
715
874
  findUser(postId) -- 'PostId' is not assignable to 'UserId'
716
875
 
717
- #id -- still a string: 5
876
+ id.length -- still a string: 5
718
877
  id:upper() -- and its methods, giving a plain string
719
878
  ```
720
879
 
@@ -753,6 +912,26 @@ parameter reads `Extract<Rows, { Page: P }>["Skills"][number]`. A type that
753
912
  waits on a type parameter — a conditional, an index, `T[K]` — is worked out
754
913
  where that parameter is.
755
914
 
915
+ **Functions compare as under `strictFunctionTypes`.** A function fits a
916
+ function type when it takes whatever that type's callers pass — its parameters
917
+ are contravariant — and needs no more arguments than they hand it: `(x: Part)
918
+ => nil` is not a `(x: Instance) => nil`, which may be called with any
919
+ instance. A method — a function taking its receiver first, `self` or `this`
920
+ — is compared both ways, as TypeScript compares methods, so an override may
921
+ narrow what it takes.
922
+
923
+ **Every way through returns.** A function that declares a return type which
924
+ does not admit `nil` has to return on every way to its end: `Not every path
925
+ returns a value` otherwise. A call that is `never` (`error(...)`) ends a way,
926
+ and so does `while (true)` with no `break` of its own.
927
+
928
+ **An `if` chain can be exhaustive.** tilua has no `switch`; an `if` /
929
+ `elseif` chain whose tests leave no value for an `else` — every member of
930
+ `x: "a" | "b"` tested — has no way past it but its branches. A function whose
931
+ chain returns in every branch needs no `return` after it, and after it `x` is
932
+ `never`, which is how `const unreachable: never = x` checks that a new
933
+ member was not forgotten.
934
+
756
935
  **Trailing commas** are allowed wherever TypeScript allows them: parameter
757
936
  lists, call arguments, generic parameters and type arguments, tables, arrays,
758
937
  tuples, imports and exports.
@@ -789,25 +968,95 @@ type says so — it is `any`, and `any` turns off every check made of it.
789
968
  **Types** — unions, intersections, tuples `[A, B]` (with a rest, `[A,
790
969
  ...B[]]`), `keyof`, `T[K]`, conditional types with
791
970
  `infer`, mapped types with `as` remapping, template literal types
792
- (`` `on${Event}` ``), and set difference `A - B`. The utility types
971
+ (`` `on${Event}` ``), and `Exclude<A, B>`. The utility types
793
972
  (`Partial`, `Pick`, `Omit`, `ReturnType`, `Parameters`, `Exclude`, …) are
794
973
  built in, and written in tilua on top of those rather than special-cased in
795
974
  the analyzer. A type library or a file may declare one again; the later
796
975
  declaration wins.
797
976
 
977
+ Type-level programs work as they do in TypeScript. A tuple may spread anywhere
978
+ (`[...A, ...B]`, `[infer H, ...infer R]`) and name its elements
979
+ (`[x: number, y?: number]`) — an element marked `?` may be left out, so
980
+ `[number, string?]` takes `[1]` and its `length` is `1 | 2`, and
981
+ `Parameters<(a: number, b?: string) => nil>` is `[a: number, b?: string]`; a
982
+ list of any length may stand before the elements written after it
983
+ (`[...unknown[], infer L]`); `T["length"]` counts a tuple, and `keyof` a list is
984
+ its positions and its `length`, `number | "length"` (`keyof string[]` is the
985
+ list's keys, `(keyof T)[]` a list of keys, as TypeScript reads them); an alias may
986
+ recurse (`type Reverse<T> = T extends [infer H, ...infer R] ? [...Reverse<R>,
987
+ H] : []`); a template literal pattern takes a string apart (`` S extends
988
+ `${infer A}.${infer B}` ``), and `infer N extends number` reads `"42"` as
989
+ `42`. `object` is anything that is not a primitive. One difference: a tuple's
990
+ positions count from 1, as Lua's do, so the first element of `T` is `T[1]`.
991
+ A recursion that never ends stops after 100 levels and gives `any`.
992
+
993
+ **What `${...}` may hold** — a template string writes each value with
994
+ `tostring`, so it takes what reads as text: a string, a number, a boolean,
995
+ `nil`, and a value that says how to print itself — a class with `__tostring`,
996
+ or one the host made (a Roblox `Instance`, a `Vector3`). A table, a list, a
997
+ function or a class instance without `__tostring` would print as its address
998
+ (`table: 0x...`), and is an error. A template literal *type* holds a string,
999
+ a number, a boolean or `nil` in each placeholder, as TypeScript's does:
1000
+ `` `a${number[]}` `` is an error, and so is a `T extends object` there.
1001
+
1002
+ A generic function may take and give variadic tuples: `<T extends unknown[]>(xs:
1003
+ [...T]): T` reads `[1, "a"]` as `[number, string]`, `(...args: [...T, string])`
1004
+ takes the last argument apart from the others, and `(fn: (...args: [...A,
1005
+ ...B]) => R, ...a: A): (...b: B) => R` binds the first arguments of `fn`.
1006
+
1007
+ `Exclude<T, U>` — what of `T` is not a `U` — is the analyzer's own, and unlike
1008
+ TypeScript's it is kept where TypeScript's would forget it: `Exclude<unknown,
1009
+ nil>` and `Exclude<any, nil>` stay, as a value known not to be `nil`, and so
1010
+ does `Exclude<string, "a">`, a string that is not `"a"` — of which `if (s ==
1011
+ "a")` is reported as a test that can never pass. Over a union it drops the
1012
+ members it takes whole (`Exclude<"a" | "b", "b">` is `"a"`), and `boolean` is
1013
+ the union `true | false`.
1014
+ tilua has no `A - B` in types; `Exclude` is the one way to write it.
1015
+
798
1016
  A call may write its type arguments out — `find<Folder>("Remotes")`,
799
1017
  `inst:WaitForChild<Folder>("Remotes")` — and a type parameter may have a
800
1018
  default (`<T = Instance>`) for the calls that do not. `a < b > (c)` is still
801
1019
  three operators: only a call after the `>` makes it type arguments.
802
1020
 
803
- `<const T>` infers an argument at its narrowest, as in TypeScript 5.
1021
+ `<const T>` infers an argument at its narrowest, as in TypeScript 5. Without it
1022
+ a literal is still kept where the function gives `T` itself back —
1023
+ `identity("x")` is `"x"`, and a `let` it is given to widens it to `string` —
1024
+ and a `K extends keyof T`, or a `T extends string`, keeps the key or the text
1025
+ written. Literals of one primitive read for one parameter are either:
1026
+ `pair(1, 2)` is `1 | 2`. `as const` makes its lists read-only:
1027
+ `[1, 2] as const` is a `readonly [1, 2]`. `ReturnType` of an overloaded
1028
+ function is its last signature's, as in TypeScript.
1029
+
1030
+ `NoInfer<T>` is `T`, except that a call does not work `T` out from an
1031
+ argument written there: `function pick<T>(a: T, fallback: NoInfer<T>): T`
1032
+ takes `T` from `a` alone, and checks `fallback` against it.
1033
+
1034
+ A type alias or an interface may say how it compares by a parameter:
1035
+ `type Getter<out T>` as `T` does, `type Setter<in T>` the other way round,
1036
+ `<in out T>` only by the same `T`. It is checked against the body —
1037
+ `type Getter<in T> = { get: () => T }` is an error — and a function's or a
1038
+ class's parameters take none.
1039
+
1040
+ `new (name: string) => Dog` is the type of a class table that builds a `Dog`:
1041
+ tilua builds with `Dog.new(name)`, so it is `{ new: (name: string) => Dog }`.
1042
+ `InstanceType<typeof Dog>` and `ConstructorParameters<typeof Dog>` read it
1043
+ back, as TypeScript's do.
804
1044
 
805
1045
  `typeof x` in a type is TypeScript's type query — the type of a value
806
1046
  (`typeof config`, `typeof config.volume`, `ReturnType<typeof f>`). Luau's
807
- `typeof(expr)` spelling works too. It is compile-time only, unrelated to the
808
- `typeof(v)` function that returns a string at runtime.
1047
+ `typeof(expr)` spelling is an error here as well. It is compile-time only, unrelated to the
1048
+ `typeof v` operator in an expression, which answers a string as the program
1049
+ runs.
809
1050
 
810
1051
  **Modules** — `import` / `export`, export lists, re-exports and `export *`.
1052
+ `export type { A }` (and `export type { A } from "./m"`) exports types and
1053
+ nothing else; naming a value there is an error.
1054
+
1055
+ **What TypeScript has and tilua does not** says what to write instead, rather
1056
+ than reading as something else: `enum`, `namespace`, `try` / `catch`,
1057
+ `switch`, `declare module` and `declare global` are each reported with the
1058
+ tilua spelling. (A name followed by `{` is otherwise a call with a table
1059
+ argument, so `enum Color { ... }` would have meant `enum(Color { ... })`.)
811
1060
 
812
1061
  **`satisfies`** — checks a value against a type without giving it that type,
813
1062
  as in TypeScript 4.9:
@@ -869,11 +1118,9 @@ analyzeTypes(program, scopes, {
869
1118
 
870
1119
  ## Known limitations
871
1120
 
872
- - `export * as ns from` and namespace imports (`import * as ns`) are not
873
- supported.
874
- - `setmetatable` and metatables are not modelled.
875
- - Accessing a property a type does not have yields `unknown` rather than an
876
- error; assigning to a `readonly` property is not reported.
1121
+ - `export * as ns from` is not supported.
1122
+ - `setmetatable` is not modelled: a table given a metatable at runtime keeps
1123
+ the type it had.
877
1124
  - A sourcemap child whose name is not an identifier (`"My Part"`) is not typed.
878
1125
 
879
1126
  ## Development