Types and use
A system's types are written once, in its Types.shot, and every file of the folder names them with no import. use replaces the require line.
You'll learn a Types file, how files see it, imports, and use.
A types file
public type Reason, public type EntryEntry and Reason, no importuseimport Entry, Reason from @shot.Walletexport type Reason = "Pickup" | "Shop"export type Entry = { Amount: number, Reason: Reason,}return {}
public type Reason = "Pickup" | "Shop"public type Entry = { Amount : number, Reason : Reason,}
public typemay leave the system;internal typestays in the folder.- Order doesn't matter: a type may use one defined below it.
- Only imports, type definitions and their docs go here (later pages add events and rules).
Using the types
--!strictlocal Types = require(script.Parent.Types)type Entry = Types.Entrylocal SUFFIX = " coins"local Coins = {}function Coins.Format(amount: number): string return tostring(amount) .. SUFFIXendfunction Coins.Line(entry: Entry): string local s = Coins.Format(entry.Amount) return s .. " for " .. entry.Reasonendreturn Coins
types script.Parent.Typeslocal SUFFIX = " coins"module Coins = { function Format(amount : number) : string return tostring(amount) .. SUFFIX end function Line(entry : Entry) : string local s = Coins.Format(entry.Amount) return s .. " for " .. entry.Reason end}
What it compiles toWallet/Types.luau
--!strict if true then return {} end --[[$public]] export type Reason = "Pickup" | "Shop" --[[$public]] export type Entry = { Amount : number, Reason : Reason, } --[[$public]] export type Coins = { Format : (amount : number) -> string, Line : (entry : Entry) -> string, }
- Each compiled file starts with an
export typeline per type of the folder: you never write those. - Every class, module and func of the folder is a type too:
Coinsis one, with no declaration. - A type in a signature (a parameter, a return, a field) belongs in
Types.shot; one written inside a file works only in that file.
Tip Another system's types come in through this folder's Types.shot, and nowhere else: import Entry, Reason from @shot.Wallet, or import * from @shot.Wallet. An import gives a type, not a value: require the system to call it.
Use
use writes the local and the require for you, named after the last part of the path:
local ReplicatedStorage = game:GetService("ReplicatedStorage")local Coins = require( ReplicatedStorage.Shot.Wallet.Coins)print(Coins.Line({ Amount = 25, Reason = "Pickup",}))
@server enableduse @shot.Wallet.Coinsprint(Coins.Line({ Amount = 25, Reason = "Pickup",}))
What it compiles toInit/Server.server.luau
--!strict local Coins = require(script.Parent.Parent.Wallet.Coins) print(Coins.Line({ Amount = 25, Reason = "Pickup", }))
A bare name, use Coins, finds the nearest Coins: this folder's files and folders, then the folder above, up to the project root. Init/ is beside Wallet/, not above it, so from there the tool asks for the path:
./Init/Server.shot:3 use Coins: no Coins in this folder or any folder above it (use looks at each folder's own files and folders, up to the project root); it is in Wallet: use @shot.Wallet.Coins 1 errors in 1 file (4 files checked, 2.4 s)
Checked
The union is a real type. A misspelt reason, Reason = "Pikup", is an error at its line:
./Init/Server.shot:5:18 TypeError: Expected this to be exactly 'Entry', but got '{| Amount: number, Reason: "Pikup" |}' caused by: Property 'Reason' is not compatible. Expected this to be exactly '"Pickup" | "Shop"', but got '"Pikup"'; none of the union options are compatible
1 errors in 1 file (4 files checked, 2.4 s)Spelt right, it checks and runs:
==== Hello [server print] 25 coins for Pickup [client:Ana print] client started ==== summary Hello OK (2 lines, 0 errors, 0.1s virtual) 1 of 1 scenario(s) passed
Add "Daily" to Reason in Types.shot and use it in Init/Server.shot: no import, no alias line, and shot check passes. Then take "Daily" out again: page 10 adds it for real.
