Type System¶
Vanguard exports Luau types from its main module and from each utility module. This guide shows reliable autocomplete patterns for services, controllers, remotes, classes, and utility objects.
Preserve the Main Module Type¶
Preferred:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Vanguard = require(ReplicatedStorage.Packages.Vanguard)
The direct path lets Studio resolve the ModuleScript and exported types.
When using WaitForChild, cast the required module:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Packages = ReplicatedStorage:WaitForChild("Packages")
local Vanguard = require(Packages:WaitForChild("Vanguard") :: ModuleScript)
:: typeof(require(ReplicatedStorage.Packages.Vanguard))
Without the cast, WaitForChild returns generic Instance, which can degrade autocomplete or produce *error-type*.
Main Exported Types¶
type VanguardType = Vanguard.Vanguard
type StartOptions = Vanguard.StartOptions
type Service = Vanguard.Service
type ServiceDefinition = Vanguard.ServiceDefinition
type Controller = Vanguard.Controller
type ControllerDefinition = Vanguard.ControllerDefinition
type Component = Vanguard.Component
type ComponentDefinition = Vanguard.ComponentDefinition
type ComponentInstance = Vanguard.ComponentInstance
type Class = Vanguard.Class
type ClassDefinition = Vanguard.ClassDefinition
type PluginDefinition = Vanguard.PluginDefinition
type PluginContext = Vanguard.PluginContext
type PluginOptions = Vanguard.PluginOptions
type Cache = Vanguard.Cache
type Cleaner = Vanguard.Cleaner
type ErrorDefinition = Vanguard.ErrorDefinition
type VanguardError = Vanguard.VanguardError
type ErrorUtil = Vanguard.ErrorUtil
type Logger = Vanguard.Logger
type MathUtil = Vanguard.MathUtil
type Promise = Vanguard.Promise
type RateLimiter = Vanguard.RateLimiter
type Signal = Vanguard.Signal
type Switch = Vanguard.Switch
type SwitchUtil = Vanguard.SwitchUtil
type RemoteSignal = Vanguard.RemoteSignal
type RemoteProperty = Vanguard.RemoteProperty
type Replicator = Vanguard.Replicator
type ReplicatorChange = Vanguard.ReplicatorChange
type ReplicatorPath = Vanguard.ReplicatorPath
type NetworkContext = Vanguard.NetworkContext
type NetworkInfo = Vanguard.NetworkInfo
type NetworkOptions = Vanguard.NetworkOptions
type NetworkRejection = Vanguard.NetworkRejection
type NetworkRule = Vanguard.NetworkRule
type NetworkStats = Vanguard.NetworkStats
type Validator = Vanguard.Validator
Strongly-Typed Services¶
Intersect your own API with the Vanguard base type:
type InventoryService = Vanguard.Service & {
Client: {
Changed: Vanguard.RemoteSignal,
State: Vanguard.Replicator,
GetItems: (self: any, player: Player) -> { string },
},
ItemsByPlayer: { [Player]: { string } },
GetItems: (self: InventoryService, player: Player) -> { string },
}
local InventoryService: InventoryService = Vanguard.CreateService({
Name = "InventoryService",
Client = {
Changed = Vanguard.CreateSignal(),
State = Vanguard.CreateReplicator({
Status = "Loading",
Items = {},
}),
},
}) :: any
The final cast may be necessary while constructing a table incrementally because generated remote markers become runtime remote objects only during startup.
ServiceWith and ControllerWith¶
Vanguard provides convenience intersections:
type InventoryService = Vanguard.ServiceWith<{
ItemsByPlayer: { [Player]: { string } },
}>
type HUDController = Vanguard.ControllerWith<{
Visible: boolean,
}>
These are equivalent to intersecting the base definitions manually.
Client Service Proxies¶
Server Client function signatures include player; client calls do not:
-- Server definition shape
GetItems: (self: any, player: Player) -> { string }
-- Client proxy shape in promise mode
GetItems: (self: any) -> Vanguard.Promise
The framework cannot automatically export a service-specific proxy type across separate server and client modules. Define a shared client-facing type when stronger client autocomplete is needed:
export type InventoryClient = {
GetItems: (self: InventoryClient) -> Vanguard.Promise,
Changed: Vanguard.RemoteSignal,
State: Vanguard.Replicator,
}
Then cast lookup:
Remote Union Types¶
Vanguard.RemoteSignal describes the shared server/client surface. Server-only methods such as FireAll are optional because the main module type is shared between runtimes.
For precise runtime types, require the utility module and use its exports:
local RemoteSignal = require(Vanguard.Util.RemoteSignal)
type ServerRemoteSignal = RemoteSignal.ServerRemoteSignal
type ClientRemoteSignal = RemoteSignal.ClientRemoteSignal
Likewise for remote properties:
local RemoteProperty = require(Vanguard.Util.RemoteProperty)
type ServerRemoteProperty = RemoteProperty.ServerRemoteProperty
type ClientRemoteProperty = RemoteProperty.ClientRemoteProperty
And for replicators:
local Replicator = require(Vanguard.Util.Replicator)
type ServerReplicator = Replicator.ServerReplicator
type ClientReplicator = Replicator.ClientReplicator
type ReplicatorChange = Replicator.Change
Utility Types¶
Every utility module exports its own detailed types:
local Cache = require(Vanguard.Util.Cache)
local Class = require(Vanguard.Util.Class)
local Cleaner = require(Vanguard.Util.Cleaner)
local Error = require(Vanguard.Util.Error)
local Math = require(Vanguard.Util.Math)
local NetworkGuard = require(Vanguard.Util.NetworkGuard)
local PluginHost = require(Vanguard.Util.PluginHost)
local Promise = require(Vanguard.Util.Promise)
local RateLimiter = require(Vanguard.Util.RateLimiter)
local Replicator = require(Vanguard.Util.Replicator)
local Switch = require(Vanguard.Util.Switch)
local Validator = require(Vanguard.Util.Validator)
type CacheOptions = Cache.Options
type ClassDefinition = Class.Definition
type Cleaner = Cleaner.Cleaner
type ErrorDefinition = Error.Definition
type VanguardError = Error.VanguardError
type GuardRule = NetworkGuard.Rule
type PluginContext = PluginHost.PluginContext
type PluginDefinition = PluginHost.PluginDefinition
type Promise = Promise.Promise
type RateLimiterOptions = RateLimiter.Options
type ReplicatorChange = Replicator.Change
type ReplicatorPath = Replicator.Path
type SwitchBuilder = Switch.Switch
type ValidatorFunction = Validator.Validator
Use utility-module types when you need fields more specific than the shared main export.
Typed Classes¶
Class construction is dynamic. Define an instance shape and cast instances at the boundary:
type Entity = {
Id: string,
GetId: (self: Entity) -> string,
IsA: (self: Entity, expected: Vanguard.Class | string) -> boolean,
}
local EntityClass = Vanguard.CreateClass({
Name = "Entity",
Constructor = function(self, id: string)
self.Id = id
end,
GetId = function(self)
return self.Id
end,
})
local entity = EntityClass("entity-1") :: Entity
Grouped class functions receive private state as their second argument. Model that implementation-only parameter locally; it is not part of the public instance shape:
type Wallet = {
GetBalance: (self: Wallet) -> number,
}
local WalletClass = Vanguard.CreateClass({
Name = "Wallet",
Private = { Balance = 0 },
Public = {
GetBalance = function(_self, private): number
return private.Balance
end,
},
Static = { Currency = "Credits" },
})
local wallet = WalletClass() :: Wallet
Typed Validators¶
Validators prove runtime shape but do not currently narrow Luau types automatically:
local valid, message = itemValidator(value)
if not valid then
return false, message
end
local item = value :: {
Id: string,
Count: number,
}
Keep the runtime schema and static type near one another to reduce drift.
Network Callback Types¶
local function authenticate(player: Player, context: Vanguard.NetworkContext): (boolean, string?)
return true
end
local function onRejected(context: Vanguard.NetworkContext, rejection: Vanguard.NetworkRejection)
print(context.RemoteName, rejection.Code)
end
context.RemoteType may be Function, Signal, Property, or
Replicator.
Plugin Types¶
type MetricsPlugin = Vanguard.PluginDefinition & {
Record: (self: MetricsPlugin, eventName: string, payload: any?) -> (),
}
local MetricsPlugin: MetricsPlugin = Vanguard.CreatePlugin({
Name = "MetricsPlugin",
Runtime = "Shared",
Record = function(self, eventName, payload)
print(eventName, payload)
end,
}) :: any
Plugin hooks receive Vanguard.PluginContext. Hook payloads are specific to
the hook name; model those payloads near the plugin when strong typing matters.
Promise Result Types¶
The bundled Promise type is intentionally broad because promises may carry multiple values:
For application-specific promises, document the resolved value at the producing method and cast after resolution when needed.
Type Caveats¶
- Runtime class inheritance is more dynamic than Luau's structural type system.
- Remote markers change into runtime objects during server startup.
- The main
Vanguardtype covers both server and client, so runtime-specific methods may be optional. GetServiceandGetControllerreturn broad values because names are dynamic.GetConfigis typed asStartOptions, but its nested tables should be treated as read-only references.