Skip to main content

Component

Bind components to Roblox instances using the Component class and CollectionService tags.

To avoid confusion of terms:

  • Component refers to this module.
  • Component Class (e.g. MyComponent through this documentation) refers to a class created via Component.new
  • Component Instance refers to an instance of a component class.
  • Roblox Instance refers to the Roblox instance to which the component instance is bound.

Methods and properties are tagged with the above terms to help clarify the level at which they are used.

Types

ExtensionFn

type ExtensionFn = (component) → ()

ExtensionShouldFn

type ExtensionShouldFn = (component) → boolean

Extension

interface Extension {
ShouldExtendExtensionShouldFn?
ShouldConstructExtensionShouldFn?
ConstructingExtensionFn?
ConstructedExtensionFn?
StartingExtensionFn?
StartedExtensionFn?
StoppingExtensionFn?
StoppedExtensionFn?
Extensions{Extension}?
Methods{[string]function}?
}

An extension allows the ability to extend the behavior of components. This is useful for adding injection systems or extending the behavior of components by wrapping around component lifecycle methods.

The ShouldConstruct function can be used to indicate if the component should actually be created. This must return true or false. A component with multiple ShouldConstruct extension functions must have them all return true in order for the component to be constructed. The ShouldConstruct function runs before all other extension functions and component lifecycle methods.

The ShouldExtend function can be used to indicate if the extension itself should be used. This can be used in order to toggle an extension on/off depending on whatever logic is appropriate. If no ShouldExtend function is provided, the extension will always be used if provided as an extension to the component.

As an example, an extension could be created to simply log when the various lifecycle stages run on the component:

local Logger = {}
function Logger.Constructing(component) print("Constructing", component) end
function Logger.Constructed(component) print("Constructed", component) end
function Logger.Starting(component) print("Starting", component) end
function Logger.Started(component) print("Started", component) end
function Logger.Stopping(component) print("Stopping", component) end
function Logger.Stopped(component) print("Stopped", component) end

local MyComponent = Component.new({Tag = "MyComponent", Extensions = {Logger}})

Sometimes it is useful for an extension to control whether or not a component should be constructed. For instance, if a component on the client should only be instantiated for the local player, an extension might look like this, assuming the instance has an attribute linking it to the player's UserId:

local player = game:GetService("Players").LocalPlayer

local OnlyLocalPlayer = {}
function OnlyLocalPlayer.ShouldConstruct(component)
	local ownerId = component.Instance:GetAttribute("OwnerId")
	return ownerId == player.UserId
end

local MyComponent = Component.new({Tag = "MyComponent", Extensions = {OnlyLocalPlayer}})

It can also be useful for an extension itself to turn on/off depending on various contexts. For example, let's take the Logger from the first example, and only use that extension if the bound instance has a Log attribute set to true:

function Logger.ShouldExtend(component)
	return component.Instance:GetAttribute("Log") == true
end

In this forked version of component, extensions can also add methods to the component class and extend other extensions via giving an extension a Methods table. For example:

local ExtendedComponentMethods = {}
function ExtendedComponentMethods.DoSomething(component)
	print("Hello World!")
end

local MyComponentExtension = {}
MyComponentExtension.Methods = ExtendedComponentMethods

This will add a method called DoSomething to the component class.

Be careful when using with ShouldExtend

It is important to note that these methods are added to the Component Class and not the Component Instance. This means that these methods will be availible regardless of whether the extension passes its shouldExtend function or not. If your code is dependent on extension methods existing only when they pass their shouldExtend function, you may want to avoid using this feature.

If you want to utilize other extensions within your extension or guarantee that the given extension is loaded onto the component before your extension, you can use the Extensions table. For example:

local SomeOtherExtension = require(somewhere.SomeOtherExtension)

local MyComponentExtension = {}
MyComponentExtension.Extensions = {SomeOtherExtension}

This will guarantee that SomeOtherExtension is added to the component and loaded before MyComponentExtension.

info

The ShouldExtend function of SomeOtherExtension will still be called independently of the ShouldExtend function of MyExtension. Under the hood this just adds the extension to the components original extension array.

ComponentConfig

interface ComponentConfig {
Tagstring--

CollectionService tag to use

Ancestors{Instance}?--

Optional array of ancestors in which components will be started

Extensions{Extension}?--

Optional array of extension objects

}

Component configuration passed to Component.new.

  • If no Ancestors option is included, it defaults to {workspace, game.Players}.
  • If no Extensions option is included, it defaults to a blank table {}.

Properties

Started

EventComponent Class
Component.Started: Signal

Fired when a new instance of a component is started.

local MyComponent = Component.new({Tag = "MyComponent"})

MyComponent.Started:Connect(function(component) end)

Stopped

EventComponent Class
Component.Stopped: Signal

Fired when an instance of a component is stopped.

local MyComponent = Component.new({Tag = "MyComponent"})

MyComponent.Stopped:Connect(function(component) end)

Instance

Component Instance
Component.Instance: Instance

A reference back to the Roblox instance from within a component instance. When a component instance is created, it is bound to a specific Roblox instance, which will always be present through the Instance property.

MyComponent.Started:Connect(function(component)
	local robloxInstance: Instance = component.Instance
	print("Component is bound to " .. robloxInstance:GetFullName())
end)

Functions

new

Component
Component.new(configComponentConfig) → ComponentClass

Create a new custom Component class.

local MyComponent = Component.new({Tag = "MyComponent"})

A full example might look like this:

local MyComponent = Component.new({
	Tag = "MyComponent",
	Ancestors = {workspace},
	Extensions = {Logger}, -- See Logger example within the example for the Extension type
})

local AnotherComponent = require(somewhere.AnotherComponent)

-- Optional if UpdateRenderStepped should use BindToRenderStep:
MyComponent.RenderPriority = Enum.RenderPriority.Camera.Value

function MyComponent:Construct()
	self.MyData = "Hello"
end

function MyComponent:Start()
	local another = self:GetComponent(AnotherComponent)
	another:DoSomething()
end

function MyComponent:Stop()
	self.MyData = "Goodbye"
end

function MyComponent:HeartbeatUpdate(dt)
end

function MyComponent:SteppedUpdate(dt)
end

function MyComponent:RenderSteppedUpdate(dt)
end

HeartbeatUpdate

Component Class
Component.HeartbeatUpdate(dtnumber) → ()

If this method is present on a component, then it will be automatically connected to RunService.Heartbeat.

Method

This is a method, not a function. This is a limitation of the documentation tool which should be fixed soon.

local MyComponent = Component.new({Tag = "MyComponent"})

function MyComponent:HeartbeatUpdate(dt)
end

SteppedUpdate

Component Class
Component.SteppedUpdate(dtnumber) → ()

If this method is present on a component, then it will be automatically connected to RunService.Stepped.

Method

This is a method, not a function. This is a limitation of the documentation tool which should be fixed soon.

local MyComponent = Component.new({Tag = "MyComponent"})

function MyComponent:SteppedUpdate(dt)
end

RenderSteppedUpdate

This item only works when running on the client. ClientComponent Class
Component.RenderSteppedUpdate(dtnumber) → ()

If this method is present on a component, then it will be automatically connected to RunService.RenderStepped. If the [Component].RenderPriority field is found, then the component will instead use RunService:BindToRenderStep() to bind the function.

Method

This is a method, not a function. This is a limitation of the documentation tool which should be fixed soon.

-- Example that uses `RunService.RenderStepped` automatically:

local MyComponent = Component.new({Tag = "MyComponent"})

function MyComponent:RenderSteppedUpdate(dt)
end
-- Example that uses `RunService:BindToRenderStep` automatically:

local MyComponent = Component.new({Tag = "MyComponent"})

-- Defining a RenderPriority will force the component to use BindToRenderStep instead
MyComponent.RenderPriority = Enum.RenderPriority.Camera.Value

function MyComponent:RenderSteppedUpdate(dt)
end

GetAll

Component Class
Component:GetAll() → {Component}

Gets a table array of all existing component objects. For example, if there was a component class linked to the "MyComponent" tag, and three Roblox instances in your game had that same tag, then calling GetAll would return the three component instances.

local MyComponent = Component.new({Tag = "MyComponent"})

-- ...

local components = MyComponent:GetAll()
for _,component in ipairs(components) do
	component:DoSomethingHere()
end

FromInstance

Component Class
Component:FromInstance(instanceInstance) → Component?

Gets an instance of a component class from the given Roblox instance. Returns nil if not found.

local MyComponent = require(somewhere.MyComponent)

local myComponentInstance = MyComponent:FromInstance(workspace.SomeInstance)

WaitForInstance

Component Class
Component:WaitForInstance(
instanceInstance,
timeoutnumber?
) → Promise<ComponentInstance>

Resolves a promise once the component instance is present on a given Roblox instance.

An optional timeout can be provided to reject the promise if it takes more than timeout seconds to resolve. If no timeout is supplied, timeout defaults to 60 seconds.

local MyComponent = require(somewhere.MyComponent)

MyComponent:WaitForInstance(workspace.SomeInstance):andThen(function(myComponentInstance)
	-- Do something with the component class
end)

UpdateAncestors

Component Class
Component:UpdateAncestors(newAncestors{Instance}) → ()

Allows for you to update the valid ancestors of a component class. This is useful if you want to give a valid ancestor that may not exist when the component is first created.

local MyComponent = Component.new({
	Tag = "MyComponent",
	Ancestors = {workspace},
})

task.defer(function()
	local newAncestors = {workspace:WaitForChild("SomeFolder")}
	MyComponent:UpdateAncestors(newAncestors)
end)

Construct

Component Class
Component:Construct() → ()

Construct is called before the component is started, and should be used to construct the component instance.

local MyComponent = Component.new({Tag = "MyComponent"})

function MyComponent:Construct()
	self.SomeData = 32
	self.OtherStuff = "HelloWorld"
end

Start

Component Class
Component:Start() → ()

Start is called when the component is started. At this point in time, it is safe to grab other components also bound to the same instance.

local MyComponent = Component.new({Tag = "MyComponent"})
local AnotherComponent = require(somewhere.AnotherComponent)

function MyComponent:Start()
	-- e.g., grab another component:
	local another = self:GetComponent(AnotherComponent)
end

Stop

Component Class
Component:Stop() → ()

Stop is called when the component is stopped. This occurs either when the bound instance is removed from one of the whitelisted ancestors or when the matching tag is removed from the instance. This also means that the instance might be destroyed, and thus it is not safe to continue using the bound instance (e.g. self.Instance) any longer.

This should be used to clean up the component.

local MyComponent = Component.new({Tag = "MyComponent"})

function MyComponent:Stop()
	self.SomeStuff:Destroy()
end

GetComponent

Component Instance
Component:GetComponent(componentClassComponentClass) → Component?

Retrieves another component instance bound to the same Roblox instance.

local MyComponent = Component.new({Tag = "MyComponent"})
local AnotherComponent = require(somewhere.AnotherComponent)

function MyComponent:Start()
	local another = self:GetComponent(AnotherComponent)
end

ForEachSibling

Component Instance
Component:ForEachSibling(
componentClassComponentClass,
fn(
componentComponent,
janiJanitor
) → ()
) → Connection

Ties a function to the lifecycle of the calling component and the equivalent component of the given componentClass. The function is run whenever a component of the given class is started. The given function passes the sibling component of the given class and a janitor to handle any connections you may make within it. The Janitor is cleaned up whenever either compenent is stopped.

local AnotherComponent = require(somewhere.AnotherComponent)

local MyComponent = Component.new({Tag = "MyComponent"})

function MyComponent:Start()
	self:ForEachSibling(AnotherComponent, function(sibling, jani)
		print(sibling.SomeProperty)
		
		jani:Add(function()
			print("Sibling component stopped")
		end)
	end)
end
Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Create a new custom Component class.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n```\n\nA full example might look like this:\n\n```lua\nlocal MyComponent = Component.new({\n\tTag = \"MyComponent\",\n\tAncestors = {workspace},\n\tExtensions = {Logger}, -- See Logger example within the example for the Extension type\n})\n\nlocal AnotherComponent = require(somewhere.AnotherComponent)\n\n-- Optional if UpdateRenderStepped should use BindToRenderStep:\nMyComponent.RenderPriority = Enum.RenderPriority.Camera.Value\n\nfunction MyComponent:Construct()\n\tself.MyData = \"Hello\"\nend\n\nfunction MyComponent:Start()\n\tlocal another = self:GetComponent(AnotherComponent)\n\tanother:DoSomething()\nend\n\nfunction MyComponent:Stop()\n\tself.MyData = \"Goodbye\"\nend\n\nfunction MyComponent:HeartbeatUpdate(dt)\nend\n\nfunction MyComponent:SteppedUpdate(dt)\nend\n\nfunction MyComponent:RenderSteppedUpdate(dt)\nend\n```",
            "params": [
                {
                    "name": "config",
                    "desc": "",
                    "lua_type": "ComponentConfig"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "ComponentClass"
                }
            ],
            "function_type": "static",
            "tags": [
                "Component"
            ],
            "source": {
                "line": 398,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "GetAll",
            "desc": "Gets a table array of all existing component objects. For example,\nif there was a component class linked to the \"MyComponent\" tag,\nand three Roblox instances in your game had that same tag, then\ncalling `GetAll` would return the three component instances.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\n-- ...\n\nlocal components = MyComponent:GetAll()\nfor _,component in ipairs(components) do\n\tcomponent:DoSomethingHere()\nend\n```",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{Component}"
                }
            ],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 655,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "FromInstance",
            "desc": "Gets an instance of a component class from the given Roblox\ninstance. Returns `nil` if not found.\n\n```lua\nlocal MyComponent = require(somewhere.MyComponent)\n\nlocal myComponentInstance = MyComponent:FromInstance(workspace.SomeInstance)\n```",
            "params": [
                {
                    "name": "instance",
                    "desc": "",
                    "lua_type": "Instance"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Component?"
                }
            ],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 672,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "WaitForInstance",
            "desc": "Resolves a promise once the component instance is present on a given\nRoblox instance.\n\nAn optional `timeout` can be provided to reject the promise if it\ntakes more than `timeout` seconds to resolve. If no timeout is\nsupplied, `timeout` defaults to 60 seconds.\n\n```lua\nlocal MyComponent = require(somewhere.MyComponent)\n\nMyComponent:WaitForInstance(workspace.SomeInstance):andThen(function(myComponentInstance)\n\t-- Do something with the component class\nend)\n```",
            "params": [
                {
                    "name": "instance",
                    "desc": "",
                    "lua_type": "Instance"
                },
                {
                    "name": "timeout",
                    "desc": "",
                    "lua_type": "number?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise<ComponentInstance>"
                }
            ],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 695,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "UpdateAncestors",
            "desc": "Allows for you to update the valid ancestors of a component class. This is useful if you want to\ngive a valid ancestor that may not exist when the component is first created.\n\n```lua\nlocal MyComponent = Component.new({\n\tTag = \"MyComponent\",\n\tAncestors = {workspace},\n})\n\ntask.defer(function()\n\tlocal newAncestors = {workspace:WaitForChild(\"SomeFolder\")}\n\tMyComponent:UpdateAncestors(newAncestors)\nend)\n```",
            "params": [
                {
                    "name": "newAncestors",
                    "desc": "",
                    "lua_type": "{Instance}"
                }
            ],
            "returns": [],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 731,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "Construct",
            "desc": "`Construct` is called before the component is started, and should be used\nto construct the component instance.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nfunction MyComponent:Construct()\n\tself.SomeData = 32\n\tself.OtherStuff = \"HelloWorld\"\nend\n```",
            "params": [],
            "returns": [],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 751,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "Start",
            "desc": "`Start` is called when the component is started. At this point in time, it\nis safe to grab other components also bound to the same instance.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\nlocal AnotherComponent = require(somewhere.AnotherComponent)\n\nfunction MyComponent:Start()\n\t-- e.g., grab another component:\n\tlocal another = self:GetComponent(AnotherComponent)\nend\n```",
            "params": [],
            "returns": [],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 768,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "Stop",
            "desc": "`Stop` is called when the component is stopped. This occurs either when the\nbound instance is removed from one of the whitelisted ancestors _or_ when\nthe matching tag is removed from the instance. This also means that the\ninstance _might_ be destroyed, and thus it is not safe to continue using\nthe bound instance (e.g. `self.Instance`) any longer.\n\nThis should be used to clean up the component.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nfunction MyComponent:Stop()\n\tself.SomeStuff:Destroy()\nend\n```",
            "params": [],
            "returns": [],
            "function_type": "method",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 788,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "GetComponent",
            "desc": "Retrieves another component instance bound to the same\nRoblox instance.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\nlocal AnotherComponent = require(somewhere.AnotherComponent)\n\nfunction MyComponent:Start()\n\tlocal another = self:GetComponent(AnotherComponent)\nend\n```",
            "params": [
                {
                    "name": "componentClass",
                    "desc": "",
                    "lua_type": "ComponentClass"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Component?"
                }
            ],
            "function_type": "method",
            "tags": [
                "Component Instance"
            ],
            "source": {
                "line": 807,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "ForEachSibling",
            "desc": "Ties a function to the lifecycle of the calling component and the equivalent component of the given\n`componentClass`. The function is run whenever a component of the given class is started. The given\nfunction passes the sibling component of the given class and a janitor to handle any connections\nyou may make within it. The Janitor is cleaned up whenever either compenent is stopped.\n\n```lua\nlocal AnotherComponent = require(somewhere.AnotherComponent)\n\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nfunction MyComponent:Start()\n\tself:ForEachSibling(AnotherComponent, function(sibling, jani)\n\t\tprint(sibling.SomeProperty)\n\t\t\n\t\tjani:Add(function()\n\t\t\tprint(\"Sibling component stopped\")\n\t\tend)\n\tend)\nend\n```",
            "params": [
                {
                    "name": "componentClass",
                    "desc": "",
                    "lua_type": "ComponentClass"
                },
                {
                    "name": "fn",
                    "desc": "",
                    "lua_type": "(component: Component, jani: Janitor) -> ()"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Connection"
                }
            ],
            "function_type": "method",
            "tags": [
                "Component Instance"
            ],
            "source": {
                "line": 837,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "HeartbeatUpdate",
            "desc": "If this method is present on a component, then it will be\nautomatically connected to `RunService.Heartbeat`.\n\n:::note Method\nThis is a method, not a function. This is a limitation\nof the documentation tool which should be fixed soon.\n:::\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nfunction MyComponent:HeartbeatUpdate(dt)\nend\n```",
            "params": [
                {
                    "name": "dt",
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "returns": [],
            "function_type": "static",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 903,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "SteppedUpdate",
            "desc": "If this method is present on a component, then it will be\nautomatically connected to `RunService.Stepped`.\n\n:::note Method\nThis is a method, not a function. This is a limitation\nof the documentation tool which should be fixed soon.\n:::\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nfunction MyComponent:SteppedUpdate(dt)\nend\n```",
            "params": [
                {
                    "name": "dt",
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "returns": [],
            "function_type": "static",
            "tags": [
                "Component Class"
            ],
            "source": {
                "line": 924,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "RenderSteppedUpdate",
            "desc": "If this method is present on a component, then it will be\nautomatically connected to `RunService.RenderStepped`. If\nthe `[Component].RenderPriority` field is found, then the\ncomponent will instead use `RunService:BindToRenderStep()`\nto bind the function.\n\n:::note Method\nThis is a method, not a function. This is a limitation\nof the documentation tool which should be fixed soon.\n:::\n\n```lua\n-- Example that uses `RunService.RenderStepped` automatically:\n\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nfunction MyComponent:RenderSteppedUpdate(dt)\nend\n```\n```lua\n-- Example that uses `RunService:BindToRenderStep` automatically:\n\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\n-- Defining a RenderPriority will force the component to use BindToRenderStep instead\nMyComponent.RenderPriority = Enum.RenderPriority.Camera.Value\n\nfunction MyComponent:RenderSteppedUpdate(dt)\nend\n```",
            "params": [
                {
                    "name": "dt",
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "returns": [],
            "function_type": "static",
            "tags": [
                "Component Class"
            ],
            "realm": [
                "Client"
            ],
            "source": {
                "line": 962,
                "path": "src/component/src/Component.lua"
            }
        }
    ],
    "properties": [
        {
            "name": "Started",
            "desc": "Fired when a new instance of a component is started.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nMyComponent.Started:Connect(function(component) end)\n```",
            "lua_type": "Signal",
            "tags": [
                "Event",
                "Component Class"
            ],
            "source": {
                "line": 179,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "Stopped",
            "desc": "Fired when an instance of a component is stopped.\n\n```lua\nlocal MyComponent = Component.new({Tag = \"MyComponent\"})\n\nMyComponent.Stopped:Connect(function(component) end)\n```",
            "lua_type": "Signal",
            "tags": [
                "Event",
                "Component Class"
            ],
            "source": {
                "line": 194,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "Instance",
            "desc": "A reference back to the _Roblox_ instance from within a _component_ instance. When\na component instance is created, it is bound to a specific Roblox instance, which\nwill always be present through the `Instance` property.\n\n```lua\nMyComponent.Started:Connect(function(component)\n\tlocal robloxInstance: Instance = component.Instance\n\tprint(\"Component is bound to \" .. robloxInstance:GetFullName())\nend)\n```",
            "lua_type": "Instance",
            "tags": [
                "Component Instance"
            ],
            "source": {
                "line": 211,
                "path": "src/component/src/Component.lua"
            }
        }
    ],
    "types": [
        {
            "name": "ExtensionFn",
            "desc": "",
            "lua_type": "(component) -> ()",
            "source": {
                "line": 11,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "ExtensionShouldFn",
            "desc": "",
            "lua_type": "(component) -> boolean",
            "source": {
                "line": 17,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "Extension",
            "desc": "An extension allows the ability to extend the behavior of\ncomponents. This is useful for adding injection systems or\nextending the behavior of components by wrapping around\ncomponent lifecycle methods.\n\nThe `ShouldConstruct` function can be used to indicate\nif the component should actually be created. This must\nreturn `true` or `false`. A component with multiple\n`ShouldConstruct` extension functions must have them _all_\nreturn `true` in order for the component to be constructed.\nThe `ShouldConstruct` function runs _before_ all other\nextension functions and component lifecycle methods.\n\nThe `ShouldExtend` function can be used to indicate if\nthe extension itself should be used. This can be used in\norder to toggle an extension on/off depending on whatever\nlogic is appropriate. If no `ShouldExtend` function is\nprovided, the extension will always be used if provided\nas an extension to the component.\n\nAs an example, an extension could be created to simply log\nwhen the various lifecycle stages run on the component:\n\n```lua\nlocal Logger = {}\nfunction Logger.Constructing(component) print(\"Constructing\", component) end\nfunction Logger.Constructed(component) print(\"Constructed\", component) end\nfunction Logger.Starting(component) print(\"Starting\", component) end\nfunction Logger.Started(component) print(\"Started\", component) end\nfunction Logger.Stopping(component) print(\"Stopping\", component) end\nfunction Logger.Stopped(component) print(\"Stopped\", component) end\n\nlocal MyComponent = Component.new({Tag = \"MyComponent\", Extensions = {Logger}})\n```\n\nSometimes it is useful for an extension to control whether or\nnot a component should be constructed. For instance, if a\ncomponent on the client should only be instantiated for the\nlocal player, an extension might look like this, assuming the\ninstance has an attribute linking it to the player's UserId:\n```lua\nlocal player = game:GetService(\"Players\").LocalPlayer\n\nlocal OnlyLocalPlayer = {}\nfunction OnlyLocalPlayer.ShouldConstruct(component)\n\tlocal ownerId = component.Instance:GetAttribute(\"OwnerId\")\n\treturn ownerId == player.UserId\nend\n\nlocal MyComponent = Component.new({Tag = \"MyComponent\", Extensions = {OnlyLocalPlayer}})\n```\n\nIt can also be useful for an extension itself to turn on/off\ndepending on various contexts. For example, let's take the\nLogger from the first example, and only use that extension\nif the bound instance has a Log attribute set to `true`:\n```lua\nfunction Logger.ShouldExtend(component)\n\treturn component.Instance:GetAttribute(\"Log\") == true\nend\n```\n\nIn this forked version of component, extensions can also add methods\nto the component class and extend other extensions via giving an extension\na `Methods` table. For example:\n\n```lua\nlocal ExtendedComponentMethods = {}\nfunction ExtendedComponentMethods.DoSomething(component)\n\tprint(\"Hello World!\")\nend\n\nlocal MyComponentExtension = {}\nMyComponentExtension.Methods = ExtendedComponentMethods\n```\nThis will add a method called `DoSomething` to the component class.\n:::caution Be careful when using with ShouldExtend\nIt is important to note that these methods are added to the `Component Class`\nand not the `Component Instance`. This means that these methods will be availible\nregardless of whether the extension passes its shouldExtend function or not. If\nyour code is dependent on extension methods existing only when they pass their \nshouldExtend function, you may want to avoid using this feature.\n:::\n\nIf you want to utilize other extensions within your extension or guarantee that the\ngiven extension is loaded onto the component before your extension, you can use\nthe `Extensions` table. For example:\n```lua\nlocal SomeOtherExtension = require(somewhere.SomeOtherExtension)\n\nlocal MyComponentExtension = {}\nMyComponentExtension.Extensions = {SomeOtherExtension}\n```\nThis will guarantee that `SomeOtherExtension` is added to the component and\nloaded before `MyComponentExtension`.\n:::info\nThe ShouldExtend function of `SomeOtherExtension` will still be called\nindependently of the ShouldExtend function of `MyExtension`. Under the hood this\njust adds the extension to the components original extension array.\n:::",
            "fields": [
                {
                    "name": "ShouldExtend",
                    "lua_type": "ExtensionShouldFn?",
                    "desc": ""
                },
                {
                    "name": "ShouldConstruct",
                    "lua_type": "ExtensionShouldFn?",
                    "desc": ""
                },
                {
                    "name": "Constructing",
                    "lua_type": "ExtensionFn?",
                    "desc": ""
                },
                {
                    "name": "Constructed",
                    "lua_type": "ExtensionFn?",
                    "desc": ""
                },
                {
                    "name": "Starting",
                    "lua_type": "ExtensionFn?",
                    "desc": ""
                },
                {
                    "name": "Started",
                    "lua_type": "ExtensionFn?",
                    "desc": ""
                },
                {
                    "name": "Stopping",
                    "lua_type": "ExtensionFn?",
                    "desc": ""
                },
                {
                    "name": "Stopped",
                    "lua_type": "ExtensionFn?",
                    "desc": ""
                },
                {
                    "name": "Extensions",
                    "lua_type": "{Extension}?",
                    "desc": ""
                },
                {
                    "name": "Methods",
                    "lua_type": "{[string]: function}?",
                    "desc": ""
                }
            ],
            "source": {
                "line": 134,
                "path": "src/component/src/Component.lua"
            }
        },
        {
            "name": "ComponentConfig",
            "desc": "Component configuration passed to `Component.new`.\n\n- If no Ancestors option is included, it defaults to `{workspace, game.Players}`.\n- If no Extensions option is included, it defaults to a blank table `{}`.",
            "fields": [
                {
                    "name": "Tag",
                    "lua_type": "string",
                    "desc": "CollectionService tag to use"
                },
                {
                    "name": "Ancestors",
                    "lua_type": "{Instance}?",
                    "desc": "Optional array of ancestors in which components will be started"
                },
                {
                    "name": "Extensions",
                    "lua_type": "{Extension}?",
                    "desc": "Optional array of extension objects"
                }
            ],
            "source": {
                "line": 159,
                "path": "src/component/src/Component.lua"
            }
        }
    ],
    "name": "Component",
    "desc": "Bind components to Roblox instances using the Component class and CollectionService tags.\n\nTo avoid confusion of terms:\n- `Component` refers to this module.\n- `Component Class` (e.g. `MyComponent` through this documentation) refers to a class created via `Component.new`\n- `Component Instance` refers to an instance of a component class.\n- `Roblox Instance` refers to the Roblox instance to which the component instance is bound.\n\nMethods and properties are tagged with the above terms to help clarify the level at which they are used.",
    "source": {
        "line": 347,
        "path": "src/component/src/Component.lua"
    }
}