Skip to main content

Janitor

Janitor is a light-weight, flexible object for cleaning up connections, instances, or anything. This implementation covers all use cases, as it doesn't force you to rely on naive typechecking to guess how an instance should be cleaned up. Instead, the developer may specify any behavior for any object.

This is the fastest OOP library on Roblox of its kind on both X86-64 as well as ARM64.

Properties

CurrentlyCleaning

This item is read only and cannot be modified. Read Only
Janitor.CurrentlyCleaning: boolean

Whether or not the Janitor is currently cleaning up.

SuppressInstanceReDestroy

since 1.15.4
</>
Janitor.SuppressInstanceReDestroy: boolean

Whether or not you want to suppress the re-destroying of instances. Default is false, which is the original behavior.

UnsafeThreadCleanup

since 1.18.0
</>
Janitor.UnsafeThreadCleanup: boolean

Whether or not to use the unsafe fast defer function for cleaning up threads. This might be able to throw, so be careful. If you're getting any thread related errors, chances are it is this.

Functions

new

Janitor.new() → Janitor

Instantiates a new Janitor object.

Is

Janitor.Is(
objectunknown--

The object you are checking.

) → boolean--

true if object is a Janitor.

Determines if the passed object is a Janitor. This checks the metatable directly.

instanceof

Janitor.instanceof(
objectunknown--

The object you are checking.

) → boolean--

true if object is a Janitor.

An alias for Janitor.Is. This is intended for roblox-ts support.

Add

Janitor:Add(
objectT,--

The object you want to clean up.

methodName?boolean | string,--

The name of the method that will be used to clean up. If not passed, it will first check if the object's type exists in TypeDefaults, and if that doesn't exist, it assumes Destroy.

index?unknown--

The index that can be used to clean up the object manually.

) → T--

The object that was passed as the first argument.

Adds an object to Janitor for later cleanup, where methodName is the key of the method within object which should be called at cleanup time. If the methodName is true the object itself will be called if it's a function or have task.cancel called on it if it is a thread. If passed an index it will occupy a namespace which can be Remove()d or overwritten. Returns the object.

Note

Objects not given an explicit methodName will be passed into the typeof function for a very naive typecheck. RBXConnections will be assigned to "Disconnect", functions and threads will be assigned to true, and everything else will default to "Destroy". Not recommended, but hey, you do you.

Luau:

local Workspace = game:GetService("Workspace")
local TweenService = game:GetService("TweenService")

local obliterator = Janitor.new()
local part = Workspace:FindFirstChild("Part") :: Part

-- Queue the Part to be Destroyed at Cleanup time
obliterator:Add(part, "Destroy")

-- Queue function to be called with `true` methodName
obliterator:Add(print, true)

-- Close a thread.
obliterator:Add(task.defer(function()
	while true do
		print("Running!")
		task.wait(0.5)
	end
end), true)

-- This implementation allows you to specify behavior for any object
obliterator:Add(TweenService:Create(part, TweenInfo.new(1), {Size = Vector3.one}), "Cancel")

-- By passing an index, the object will occupy a namespace
-- If "CurrentTween" already exists, it will call :Remove("CurrentTween") before writing
obliterator:Add(TweenService:Create(part, TweenInfo.new(1), {Size = Vector3.one}), "Destroy", "CurrentTween")

TypeScript:

import { Workspace, TweenService } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor<{ CurrentTween: Tween }>();
const part = Workspace.FindFirstChild("Part") as Part;

// Queue the part to be Destroyed at Cleanup time
obliterator.Add(part, "Destroy");

// Queue function to be called with `true` methodName
obliterator.Add(print, true);

// Close a thread.
obliterator.Add(task.defer(() => {
	while (true) {
		print("Running!");
		task.wait(0.5);
	}
}), true);

// This implementation allows you to specify behavior for any object
obliterator.Add(TweenService.Create(part, new TweenInfo(1), { Size: Vector3.one }), "Cancel");

// By passing an index, the object will occupy a namespace
// If "CurrentTween" already exists, it will call :Remove("CurrentTween") before writing
obliterator.Add(TweenService.Create(part, new TweenInfo(1), { Size: Vector3.one }), "Destroy", "CurrentTween");

AddObject

since v1.16.0
</>
Janitor:AddObject(
constructor{new(A...) → T},--

The constructor for the object you want to add to the Janitor.

methodName?boolean | string,--

The name of the method that will be used to clean up. If not passed, it will first check if the object's type exists in TypeDefaults, and if that doesn't exist, it assumes Destroy.

index?unknown,--

The index that can be used to clean up the object manually.

...A...--

The arguments that will be passed to the constructor.

) → T--

The object that was passed as the first argument.

Constructs an object for you and adds it to the Janitor. It's really just shorthand for Janitor:Add(object.new(), methodName, index).

Luau:

local obliterator = Janitor.new()
local subObliterator = obliterator:AddObject(Janitor, "Destroy")
-- subObliterator is another Janitor!

TypeScript:

import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor();
const subObliterator = obliterator.AddObject(Janitor, "Destroy");

Get

Janitor:Get(
indexunknown--

The index that the object is stored under.

) → unknown?--

This will return the object if it is found, but it won't return anything if it doesn't exist.

Gets whatever object is stored with the given index, if it exists. This was added since Maid allows getting the task using __index.

Luau:

local obliterator = Janitor.new()
obliterator:Add(Workspace.Baseplate, "Destroy", "Baseplate")
print(obliterator:Get("Baseplate")) -- Returns Baseplate.

TypeScript:

import { Workspace } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor<{ Baseplate: Part }>();
obliterator.Add(Workspace.FindFirstChild("Baseplate") as Part, "Destroy", "Baseplate");
print(obliterator.Get("Baseplate")); // Returns Baseplate.

AddPromise

Janitor:AddPromise(
promiseObjectPromise,--

The promise you want to add to the Janitor.

index?unknown--

The index that can be used to clean up the object manually.

) → Promise

Adds a Promise to the Janitor. If the Janitor is cleaned up and the Promise is not completed, the Promise will be cancelled.

Luau:

local obliterator = Janitor.new()
obliterator:AddPromise(Promise.delay(3)):andThenCall(print, "Finished!"):catch(warn)
task.wait(1)
obliterator:Cleanup()

TypeScript:

import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor();
obliterator.AddPromise(Promise.delay(3)).andThenCall(print, "Finished!").catch(warn);
task.wait(1);
obliterator.Cleanup();

Errors

TypeDescription
NotAPromiseErrorThrown if the promise is not a Promise.

Remove

Janitor:Remove(
indexunknown--

The index you want to remove.

) → Janitor

Cleans up whatever Object was set to this namespace by the 3rd parameter of Janitor.Add.

Luau:

local obliterator = Janitor.new()
obliterator:Add(workspace.Baseplate, "Destroy", "Baseplate")
obliterator:Remove("Baseplate")

TypeScript:

import { Workspace } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor<{ Baseplate: Part }>();
obliterator.Add(Workspace.FindFirstChild("Baseplate") as Part, "Destroy", "Baseplate");
obliterator.Remove("Baseplate");

RemoveNoClean

since v1.15.0
</>
Janitor:RemoveNoClean(
indexunknown--

The index you are removing.

) → Janitor

Removes an object from the Janitor without running a cleanup.

Luau

local obliterator = Janitor.new()
obliterator:Add(function()
	print("Removed!")
end, true, "Function")

obliterator:RemoveNoClean("Function") -- Does not print.

TypeScript:

import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor<{ Function: () => void }>();
obliterator.Add(() => print("Removed!"), true, "Function");

obliterator.RemoveNoClean("Function"); // Does not print.

RemoveList

since v1.14.0
</>
Janitor:RemoveList(
...unknown--

The indices you want to remove.

) → Janitor

Cleans up multiple objects at once.

Luau:

local obliterator = Janitor.new()
obliterator:Add(function()
	print("Removed One")
end, true, "One")

obliterator:Add(function()
	print("Removed Two")
end, true, "Two")

obliterator:Add(function()
	print("Removed Three")
end, true, "Three")

obliterator:RemoveList("One", "Two", "Three") -- Prints "Removed One", "Removed Two", and "Removed Three"

TypeScript:

import { Janitor } from "@rbxts/janitor";

type NoOp = () => void

const obliterator = new Janitor<{ One: NoOp, Two: NoOp, Three: NoOp }>();
obliterator.Add(() => print("Removed One"), true, "One");
obliterator.Add(() => print("Removed Two"), true, "Two");
obliterator.Add(() => print("Removed Three"), true, "Three");

obliterator.RemoveList("One", "Two", "Three"); // Prints "Removed One", "Removed Two", and "Removed Three"

RemoveListNoClean

since v1.15.0
</>
Janitor:RemoveListNoClean(
...unknown--

The indices you want to remove.

) → Janitor

Cleans up multiple objects at once without running their cleanup.

Luau:

local obliterator = Janitor.new()
obliterator:Add(function()
	print("Removed One")
end, true, "One")

obliterator:Add(function()
	print("Removed Two")
end, true, "Two")

obliterator:Add(function()
	print("Removed Three")
end, true, "Three")

obliterator:RemoveListNoClean("One", "Two", "Three") -- Nothing is printed.

TypeScript:

import { Janitor } from "@rbxts/janitor";

type NoOperation = () => void

const obliterator = new Janitor<{ One: NoOperation, Two: NoOperation, Three: NoOperation }>();
obliterator.Add(() => print("Removed One"), true, "One");
obliterator.Add(() => print("Removed Two"), true, "Two");
obliterator.Add(() => print("Removed Three"), true, "Three");

obliterator.RemoveListNoClean("One", "Two", "Three"); // Nothing is printed.

GetAll

since v1.15.1
</>
Janitor:GetAll() → {[any]any}

Returns a frozen copy of the Janitor's indices.

Luau:

local obliterator = Janitor.new()
obliterator:Add(Workspace.Baseplate, "Destroy", "Baseplate")
print(obliterator:GetAll().Baseplate) -- Prints Baseplate.

TypeScript:

import { Workspace } from "@rbxts/services";
import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor<{ Baseplate: Part }>();
obliterator.Add(Workspace.FindFirstChild("Baseplate") as Part, "Destroy", "Baseplate");
print(obliterator.GetAll().Baseplate); // Prints Baseplate.

Cleanup

Janitor:Cleanup() → ()

Calls each object's methodName (or calls the object if methodName == true) and removes them from the Janitor. Also clears the namespace. This function is also called when you call a Janitor object (so it can be used as a destructor callback).

Luau:

obliterator:Cleanup() -- Valid.
obliterator() -- Also valid.

TypeScript:

obliterator.Cleanup()
// TypeScript version doesn't support the __call method of cleaning.

Destroy

Janitor:Destroy() → ()

Calls Janitor.Cleanup and renders the Janitor unusable.

Metatable Removal

Running this will make any further attempts to call a method of Janitor error.

LinkToInstance

Janitor:LinkToInstance(
objectInstance,--

The instance you want to link the Janitor to.

allowMultiple?boolean--

Whether or not to allow multiple links on the same Janitor.

) → RBXScriptConnection--

A RBXScriptConnection that can be disconnected to prevent the cleanup of LinkToInstance.

"Links" this Janitor to an Instance, such that the Janitor will Cleanup when the Instance is Destroy()d and garbage collected. A Janitor may only be linked to one instance at a time, unless allowMultiple is true. When called with a truthy allowMultiple parameter, the Janitor will "link" the Instance without overwriting any previous links, and will also not be overwritable. When called with a falsy allowMultiple parameter, the Janitor will overwrite the previous link which was also called with a falsy allowMultiple parameter, if applicable.

Luau:

local obliterator = Janitor.new()

obliterator:Add(function()
	print("Cleaning up!")
end, true)

do
	local folder = Instance.new("Folder")
	obliterator:LinkToInstance(folder)
	folder:Destroy()
end

TypeScript:

import { Janitor } from "@rbxts/janitor";

const obliterator = new Janitor();
obliterator.Add(() => print("Cleaning up!"), true);

{
	const folder = new Instance("Folder");
	obliterator.LinkToInstance(folder, false);
	folder.Destroy();
}

LinkToInstances

Janitor:LinkToInstances(
...Instance--

All the Instances you want linked.

) → Janitor--

A new Janitor that can be used to manually disconnect all LinkToInstances.

Links several instances to a new Janitor, which is then returned.

Show raw api
{
    "functions": [
        {
            "name": "new",
            "desc": "Instantiates a new Janitor object.",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Janitor"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 162,
                "path": "src/init.luau"
            }
        },
        {
            "name": "Is",
            "desc": "Determines if the passed object is a Janitor. This checks the metatable\ndirectly.",
            "params": [
                {
                    "name": "object",
                    "desc": "The object you are checking.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "`true` if `object` is a Janitor.",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 175,
                "path": "src/init.luau"
            }
        },
        {
            "name": "instanceof",
            "desc": "An alias for [Janitor.Is]. This is intended for roblox-ts support.",
            "params": [
                {
                    "name": "object",
                    "desc": "The object you are checking.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "`true` if `object` is a Janitor.",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 188,
                "path": "src/init.luau"
            }
        },
        {
            "name": "Add",
            "desc": "Adds an `object` to Janitor for later cleanup, where `methodName` is the\nkey of the method within `object` which should be called at cleanup time.\nIf the `methodName` is `true` the `object` itself will be called if it's a\nfunction or have `task.cancel` called on it if it is a thread. If passed an\nindex it will occupy a namespace which can be `Remove()`d or overwritten.\nReturns the `object`.\n\n:::info Note\nObjects not given an explicit `methodName` will be passed into the `typeof`\nfunction for a very naive typecheck. RBXConnections will be assigned to\n\"Disconnect\", functions and threads will be assigned to `true`, and\neverything else will default to \"Destroy\". Not recommended, but hey, you do\nyou.\n:::\n\n### Luau:\n\n```lua\nlocal Workspace = game:GetService(\"Workspace\")\nlocal TweenService = game:GetService(\"TweenService\")\n\nlocal obliterator = Janitor.new()\nlocal part = Workspace:FindFirstChild(\"Part\") :: Part\n\n-- Queue the Part to be Destroyed at Cleanup time\nobliterator:Add(part, \"Destroy\")\n\n-- Queue function to be called with `true` methodName\nobliterator:Add(print, true)\n\n-- Close a thread.\nobliterator:Add(task.defer(function()\n\twhile true do\n\t\tprint(\"Running!\")\n\t\ttask.wait(0.5)\n\tend\nend), true)\n\n-- This implementation allows you to specify behavior for any object\nobliterator:Add(TweenService:Create(part, TweenInfo.new(1), {Size = Vector3.one}), \"Cancel\")\n\n-- By passing an index, the object will occupy a namespace\n-- If \"CurrentTween\" already exists, it will call :Remove(\"CurrentTween\") before writing\nobliterator:Add(TweenService:Create(part, TweenInfo.new(1), {Size = Vector3.one}), \"Destroy\", \"CurrentTween\")\n```\n\n### TypeScript:\n\n```ts\nimport { Workspace, TweenService } from \"@rbxts/services\";\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor<{ CurrentTween: Tween }>();\nconst part = Workspace.FindFirstChild(\"Part\") as Part;\n\n// Queue the part to be Destroyed at Cleanup time\nobliterator.Add(part, \"Destroy\");\n\n// Queue function to be called with `true` methodName\nobliterator.Add(print, true);\n\n// Close a thread.\nobliterator.Add(task.defer(() => {\n\twhile (true) {\n\t\tprint(\"Running!\");\n\t\ttask.wait(0.5);\n\t}\n}), true);\n\n// This implementation allows you to specify behavior for any object\nobliterator.Add(TweenService.Create(part, new TweenInfo(1), { Size: Vector3.one }), \"Cancel\");\n\n// By passing an index, the object will occupy a namespace\n// If \"CurrentTween\" already exists, it will call :Remove(\"CurrentTween\") before writing\nobliterator.Add(TweenService.Create(part, new TweenInfo(1), { Size: Vector3.one }), \"Destroy\", \"CurrentTween\");\n```",
            "params": [
                {
                    "name": "object",
                    "desc": "The object you want to clean up.",
                    "lua_type": "T"
                },
                {
                    "name": "methodName?",
                    "desc": "The name of the method that will be used to clean up. If not passed, it will first check if the object's type exists in TypeDefaults, and if that doesn't exist, it assumes `Destroy`.",
                    "lua_type": "boolean | string"
                },
                {
                    "name": "index?",
                    "desc": "The index that can be used to clean up the object manually.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "The object that was passed as the first argument.",
                    "lua_type": "T"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 388,
                "path": "src/init.luau"
            }
        },
        {
            "name": "AddObject",
            "desc": "Constructs an object for you and adds it to the Janitor. It's really just\nshorthand for `Janitor:Add(object.new(), methodName, index)`.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nlocal subObliterator = obliterator:AddObject(Janitor, \"Destroy\")\n-- subObliterator is another Janitor!\n```\n\n### TypeScript:\n\n```ts\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor();\nconst subObliterator = obliterator.AddObject(Janitor, \"Destroy\");\n```",
            "params": [
                {
                    "name": "constructor",
                    "desc": "The constructor for the object you want to add to the Janitor.",
                    "lua_type": "{new: (A...) -> T}"
                },
                {
                    "name": "methodName?",
                    "desc": "The name of the method that will be used to clean up. If not passed, it will first check if the object's type exists in TypeDefaults, and if that doesn't exist, it assumes `Destroy`.",
                    "lua_type": "boolean | string"
                },
                {
                    "name": "index?",
                    "desc": "The index that can be used to clean up the object manually.",
                    "lua_type": "unknown"
                },
                {
                    "name": "...",
                    "desc": "The arguments that will be passed to the constructor.",
                    "lua_type": "A..."
                }
            ],
            "returns": [
                {
                    "desc": "The object that was passed as the first argument.",
                    "lua_type": "T"
                }
            ],
            "function_type": "method",
            "since": "v1.16.0",
            "source": {
                "line": 418,
                "path": "src/init.luau"
            }
        },
        {
            "name": "Get",
            "desc": "Gets whatever object is stored with the given index, if it exists. This was\nadded since Maid allows getting the task using `__index`.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:Add(Workspace.Baseplate, \"Destroy\", \"Baseplate\")\nprint(obliterator:Get(\"Baseplate\")) -- Returns Baseplate.\n```\n\n### TypeScript:\n\n```ts\nimport { Workspace } from \"@rbxts/services\";\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor<{ Baseplate: Part }>();\nobliterator.Add(Workspace.FindFirstChild(\"Baseplate\") as Part, \"Destroy\", \"Baseplate\");\nprint(obliterator.Get(\"Baseplate\")); // Returns Baseplate.\n```",
            "params": [
                {
                    "name": "index",
                    "desc": "The index that the object is stored under.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "This will return the object if it is found, but it won't return anything if it doesn't exist.",
                    "lua_type": "unknown?"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 456,
                "path": "src/init.luau"
            }
        },
        {
            "name": "AddPromise",
            "desc": "Adds a [Promise](https://github.com/evaera/roblox-lua-promise) to the\nJanitor. If the Janitor is cleaned up and the Promise is not completed, the\nPromise will be cancelled.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:AddPromise(Promise.delay(3)):andThenCall(print, \"Finished!\"):catch(warn)\ntask.wait(1)\nobliterator:Cleanup()\n```\n\n### TypeScript:\n\n```ts\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor();\nobliterator.AddPromise(Promise.delay(3)).andThenCall(print, \"Finished!\").catch(warn);\ntask.wait(1);\nobliterator.Cleanup();\n```",
            "params": [
                {
                    "name": "promiseObject",
                    "desc": "The promise you want to add to the Janitor.",
                    "lua_type": "Promise"
                },
                {
                    "name": "index?",
                    "desc": "The index that can be used to clean up the object manually.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Promise"
                }
            ],
            "function_type": "method",
            "errors": [
                {
                    "lua_type": "NotAPromiseError",
                    "desc": "Thrown if the promise is not a Promise."
                }
            ],
            "source": {
                "line": 489,
                "path": "src/init.luau"
            }
        },
        {
            "name": "Remove",
            "desc": "Cleans up whatever `Object` was set to this namespace by the 3rd parameter of [Janitor.Add](#Add).\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:Add(workspace.Baseplate, \"Destroy\", \"Baseplate\")\nobliterator:Remove(\"Baseplate\")\n```\n\n### TypeScript:\n\n```ts\nimport { Workspace } from \"@rbxts/services\";\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor<{ Baseplate: Part }>();\nobliterator.Add(Workspace.FindFirstChild(\"Baseplate\") as Part, \"Destroy\", \"Baseplate\");\nobliterator.Remove(\"Baseplate\");\n```",
            "params": [
                {
                    "name": "index",
                    "desc": "The index you want to remove.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Janitor"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 554,
                "path": "src/init.luau"
            }
        },
        {
            "name": "RemoveNoClean",
            "desc": "Removes an object from the Janitor without running a cleanup.\n\n### Luau\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:Add(function()\n\tprint(\"Removed!\")\nend, true, \"Function\")\n\nobliterator:RemoveNoClean(\"Function\") -- Does not print.\n```\n\n### TypeScript:\n\n```ts\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor<{ Function: () => void }>();\nobliterator.Add(() => print(\"Removed!\"), true, \"Function\");\n\nobliterator.RemoveNoClean(\"Function\"); // Does not print.\n```",
            "params": [
                {
                    "name": "index",
                    "desc": "The index you are removing.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Janitor"
                }
            ],
            "function_type": "method",
            "since": "v1.15.0",
            "source": {
                "line": 588,
                "path": "src/init.luau"
            }
        },
        {
            "name": "RemoveList",
            "desc": "Cleans up multiple objects at once.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:Add(function()\n\tprint(\"Removed One\")\nend, true, \"One\")\n\nobliterator:Add(function()\n\tprint(\"Removed Two\")\nend, true, \"Two\")\n\nobliterator:Add(function()\n\tprint(\"Removed Three\")\nend, true, \"Three\")\n\nobliterator:RemoveList(\"One\", \"Two\", \"Three\") -- Prints \"Removed One\", \"Removed Two\", and \"Removed Three\"\n```\n\n### TypeScript:\n\n```ts\nimport { Janitor } from \"@rbxts/janitor\";\n\ntype NoOp = () => void\n\nconst obliterator = new Janitor<{ One: NoOp, Two: NoOp, Three: NoOp }>();\nobliterator.Add(() => print(\"Removed One\"), true, \"One\");\nobliterator.Add(() => print(\"Removed Two\"), true, \"Two\");\nobliterator.Add(() => print(\"Removed Three\"), true, \"Three\");\n\nobliterator.RemoveList(\"One\", \"Two\", \"Three\"); // Prints \"Removed One\", \"Removed Two\", and \"Removed Three\"\n```",
            "params": [
                {
                    "name": "...",
                    "desc": "The indices you want to remove.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Janitor"
                }
            ],
            "function_type": "method",
            "since": "v1.14.0",
            "source": {
                "line": 643,
                "path": "src/init.luau"
            }
        },
        {
            "name": "RemoveListNoClean",
            "desc": "Cleans up multiple objects at once without running their cleanup.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:Add(function()\n\tprint(\"Removed One\")\nend, true, \"One\")\n\nobliterator:Add(function()\n\tprint(\"Removed Two\")\nend, true, \"Two\")\n\nobliterator:Add(function()\n\tprint(\"Removed Three\")\nend, true, \"Three\")\n\nobliterator:RemoveListNoClean(\"One\", \"Two\", \"Three\") -- Nothing is printed.\n```\n\n### TypeScript:\n\n```ts\nimport { Janitor } from \"@rbxts/janitor\";\n\ntype NoOperation = () => void\n\nconst obliterator = new Janitor<{ One: NoOperation, Two: NoOperation, Three: NoOperation }>();\nobliterator.Add(() => print(\"Removed One\"), true, \"One\");\nobliterator.Add(() => print(\"Removed Two\"), true, \"Two\");\nobliterator.Add(() => print(\"Removed Three\"), true, \"Three\");\n\nobliterator.RemoveListNoClean(\"One\", \"Two\", \"Three\"); // Nothing is printed.\n```",
            "params": [
                {
                    "name": "...",
                    "desc": "The indices you want to remove.",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Janitor"
                }
            ],
            "function_type": "method",
            "since": "v1.15.0",
            "source": {
                "line": 714,
                "path": "src/init.luau"
            }
        },
        {
            "name": "GetAll",
            "desc": "Returns a frozen copy of the Janitor's indices.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\nobliterator:Add(Workspace.Baseplate, \"Destroy\", \"Baseplate\")\nprint(obliterator:GetAll().Baseplate) -- Prints Baseplate.\n```\n\n### TypeScript:\n\n```ts\nimport { Workspace } from \"@rbxts/services\";\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor<{ Baseplate: Part }>();\nobliterator.Add(Workspace.FindFirstChild(\"Baseplate\") as Part, \"Destroy\", \"Baseplate\");\nprint(obliterator.GetAll().Baseplate); // Prints Baseplate.\n```",
            "params": [],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "{[any]: any}"
                }
            ],
            "function_type": "method",
            "since": "v1.15.1",
            "source": {
                "line": 799,
                "path": "src/init.luau"
            }
        },
        {
            "name": "Cleanup",
            "desc": "Calls each object's `methodName` (or calls the object if\n`methodName == true`) and removes them from the Janitor. Also clears the\nnamespace. This function is also called when you call a Janitor object (so\nit can be used as a destructor callback).\n\n### Luau:\n\n```lua\nobliterator:Cleanup() -- Valid.\nobliterator() -- Also valid.\n```\n\n### TypeScript:\n\n```ts\nobliterator.Cleanup()\n// TypeScript version doesn't support the __call method of cleaning.\n```",
            "params": [],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 827,
                "path": "src/init.luau"
            }
        },
        {
            "name": "Destroy",
            "desc": "Calls [Janitor.Cleanup](#Cleanup) and renders the Janitor unusable.\n\n:::warning Metatable Removal\nRunning this will make any further attempts to call a method of Janitor\nerror.\n:::",
            "params": [],
            "returns": [],
            "function_type": "method",
            "source": {
                "line": 907,
                "path": "src/init.luau"
            }
        },
        {
            "name": "LinkToInstance",
            "desc": "\"Links\" this Janitor to an Instance, such that the Janitor will `Cleanup`\nwhen the Instance is `Destroy()`d and garbage collected. A Janitor may only\nbe linked to one instance at a time, unless `allowMultiple` is true. When\ncalled with a truthy `allowMultiple` parameter, the Janitor will \"link\" the\nInstance without overwriting any previous links, and will also not be\noverwritable. When called with a falsy `allowMultiple` parameter, the\nJanitor will overwrite the previous link which was also called with a falsy\n`allowMultiple` parameter, if applicable.\n\n### Luau:\n\n```lua\nlocal obliterator = Janitor.new()\n\nobliterator:Add(function()\n\tprint(\"Cleaning up!\")\nend, true)\n\ndo\n\tlocal folder = Instance.new(\"Folder\")\n\tobliterator:LinkToInstance(folder)\n\tfolder:Destroy()\nend\n```\n\n### TypeScript:\n\n```ts\nimport { Janitor } from \"@rbxts/janitor\";\n\nconst obliterator = new Janitor();\nobliterator.Add(() => print(\"Cleaning up!\"), true);\n\n{\n\tconst folder = new Instance(\"Folder\");\n\tobliterator.LinkToInstance(folder, false);\n\tfolder.Destroy();\n}\n```",
            "params": [
                {
                    "name": "object",
                    "desc": "The instance you want to link the Janitor to.",
                    "lua_type": "Instance"
                },
                {
                    "name": "allowMultiple?",
                    "desc": "Whether or not to allow multiple links on the same Janitor.",
                    "lua_type": "boolean"
                }
            ],
            "returns": [
                {
                    "desc": "A RBXScriptConnection that can be disconnected to prevent the cleanup of LinkToInstance.",
                    "lua_type": "RBXScriptConnection"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 971,
                "path": "src/init.luau"
            }
        },
        {
            "name": "LinkToInstances",
            "desc": "Links several instances to a new Janitor, which is then returned.",
            "params": [
                {
                    "name": "...",
                    "desc": "All the Instances you want linked.",
                    "lua_type": "Instance"
                }
            ],
            "returns": [
                {
                    "desc": "A new Janitor that can be used to manually disconnect all LinkToInstances.",
                    "lua_type": "Janitor"
                }
            ],
            "function_type": "method",
            "source": {
                "line": 981,
                "path": "src/init.luau"
            }
        }
    ],
    "properties": [
        {
            "name": "CurrentlyCleaning",
            "desc": "Whether or not the Janitor is currently cleaning up.",
            "lua_type": "boolean",
            "readonly": true,
            "source": {
                "line": 134,
                "path": "src/init.luau"
            }
        },
        {
            "name": "SuppressInstanceReDestroy",
            "desc": "Whether or not you want to suppress the re-destroying of instances. Default\nis false, which is the original behavior.",
            "lua_type": "boolean",
            "since": "1.15.4",
            "source": {
                "line": 142,
                "path": "src/init.luau"
            }
        },
        {
            "name": "UnsafeThreadCleanup",
            "desc": "Whether or not to use the unsafe fast defer function for cleaning up\nthreads. This might be able to throw, so be careful. If you're getting any\nthread related errors, chances are it is this.",
            "lua_type": "boolean",
            "since": "1.18.0",
            "source": {
                "line": 151,
                "path": "src/init.luau"
            }
        }
    ],
    "types": [],
    "name": "Janitor",
    "desc": "Janitor is a light-weight, flexible object for cleaning up connections,\ninstances, or anything. This implementation covers all use cases, as it\ndoesn't force you to rely on naive typechecking to guess how an instance\nshould be cleaned up. Instead, the developer may specify any behavior for\nany object.\n\nThis is the fastest OOP library on Roblox of its kind on both X86-64 as\nwell as ARM64.",
    "source": {
        "line": 118,
        "path": "src/init.luau"
    }
}