Skip to content

Package Type Extraction

Installed Luau packages don’t ship TypeScript types, so importing them would normally resolve to any. The rbx-tsx types command reads each package’s Luau source and emits a declare module block, giving your imports real types.

Terminal window
wally install # or: pesde install
rbx-tsx types # reads wally.toml / pesde.toml + all package folders
FlagDescriptionDefault
-o, --output <dir>Output directory for the generated .d.ts filestypes/packages
-f, --forceOverwrite existing .d.ts files next to local modulesfalse

All install locations are searched — Packages/, ServerPackages/, and DevPackages/ for wally, roblox_packages/ and roblox_server_packages/ for pesde — so [server-dependencies] and [dev-dependencies] resolve like regular dependencies.

Add the output directory to your tsconfig.json include (e.g. "types/**/*") so TypeScript picks the declarations up. Re-run after installing or updating packages.

Pass a .luau file or a directory to generate declarations for your own hand-written Luau modules instead of installed packages:

Terminal window
rbx-tsx types src/util.luau # emits src/util.d.ts
rbx-tsx types src/ # one sibling .d.ts per module under src/

The .d.ts lands next to the .luau file so relative imports from TypeScript resolve to it. .server/.client scripts and package/tooling directories are skipped, and an existing .d.ts is never overwritten without --force.

For each dependency it reads the package’s Luau source, extracts export type aliases and the module’s exported shape, and emits a declare module block:

  • Exported type aliases (with generics)
  • Function signatures, including generic function types (<T>(x: T) -> T)
  • Table / record shapes
  • Unions, optionals
  • Explicit type annotations on the returned module local (local M: Module = ...)
  • Common ecosystem aliases (ArrayT[], Map/Set → TS Map/Set, ObjectRecord<string, any>)

A leading self parameter on a member is dropped from the TS signature when it refers to the enclosing table (rbx-tsx compiles member calls with colon syntax, which binds the receiver implicitly); a differently-typed self — e.g. a callback field — keeps its slot.

Constructs the extractor can’t resolve degrade gracefully to any rather than failing:

  • Metatable classes and typeof(setmetatable(...))
  • Cross-module type references
  • Luau type functions

Packages that ship bundled hand-written types (react, react-roblox, react-dom) are skipped.