Repository: hikari-py/hikari
Pull request #1506 (2023-02-10 07:50:05)

Fix sticker image_url property
### Summary
Speculative fix for `image_url` possibly not accounting for GIF stickers, however it could also be possible that Discord just converts these to `.apng`s, sadly I wasn't able to verify as the client keeps refusing my gif uploads as "Invalid payload".

### Checklist
<!-- Make sure to tick all the following boxes by putting an `x` in between (like this `[x]`) -->
- [x] I have run `nox` and all the pipelines have passed.
- [ ] I have made unittests according to the code I have added/modified/deleted.



Patch:
diff --git a/changes/1506.bugfix.md b/changes/1506.bugfix.md
new file mode 100644
index 00000000..ff0443c5
--- /dev/null
+++ b/changes/1506.bugfix.md
@@ -0,0 +1,1 @@
+Fix `PartialSticker.image_url` not accounting for stickers with GIF format.
diff --git a/changes/1508.feature.md b/changes/1508.feature.md
new file mode 100644
index 00000000..c55ab7b0
--- /dev/null
+++ b/changes/1508.feature.md
@@ -0,0 +1,1 @@
+`hikari.impl.special_endpoints.ChannelSelectMenuBuilder` and `hikari.impl.special_endpoints.TextSelectMenuBuilder` are now both exported directly on `hikari.impl`.
diff --git a/changes/1509.breaking.md b/changes/1509.breaking.md
new file mode 100644
index 00000000..5ecc767b
--- /dev/null
+++ b/changes/1509.breaking.md
@@ -0,0 +1,2 @@
+`type` can no-longer be specified while initialise `hikari.impl.special_endpoints.TextSelectMenuBuilder` and `hikari.impl.special_endpoints.ChannelSelectMenuBuilder`.
+`hikari.api.special_endpoints.SelectOptionBuilder` no-longer inherits from `hikari.api.special_endpoints.ComponentBuilder` (but it still has a `build` method).
diff --git a/changes/1509.feature.md b/changes/1509.feature.md
new file mode 100644
index 00000000..75ccc05e
--- /dev/null
+++ b/changes/1509.feature.md
@@ -0,0 +1,1 @@
+`type` property to the component builders.
diff --git a/changes/1516.feature.md b/changes/1516.feature.md
new file mode 100644
index 00000000..bd0398e4
--- /dev/null
+++ b/changes/1516.feature.md
@@ -0,0 +1,1 @@
+Traits now use `abc.abstractmethod`. This gives better type errors.
diff --git a/changes/1527.feature.md b/changes/1527.feature.md
new file mode 100644
index 00000000..9bf02ed7
--- /dev/null
+++ b/changes/1527.feature.md
@@ -0,0 +1,1 @@
+`token_type` now defaults to `"Bot"` when initialising `RESTBot` with a string token.
diff --git a/changes/1529.bugfix.md b/changes/1529.bugfix.md
new file mode 100644
index 00000000..c9c0331e
--- /dev/null
+++ b/changes/1529.bugfix.md
@@ -0,0 +1,1 @@
+Await bucket manager gc task to completion when closing
diff --git a/dev-requirements/coverage.txt b/dev-requirements/coverage.txt
index a4665e60..f80f7edf 100644
--- a/dev-requirements/coverage.txt
+++ b/dev-requirements/coverage.txt
@@ -1,1 +1,1 @@
-coverage[toml]==7.1.0
+coverage[toml]==7.2.1
diff --git a/dev-requirements/flake8.txt b/dev-requirements/flake8.txt
index 4ca829f5..7c7a4e33 100644
--- a/dev-requirements/flake8.txt
+++ b/dev-requirements/flake8.txt
@@ -18,7 +18,7 @@ flake8-mutable==1.2.0                   # mutable default argument detection
 flake8-pep3101==2.0.0                   # new-style format strings only
 flake8-print==5.0.0                     # complain about print statements in code
 flake8-printf-formatting==1.1.2         # forbey printf-style python2 string formatting
-flake8-pytest-style==1.7.0              # pytest checks
+flake8-pytest-style==1.7.2              # pytest checks
 flake8-raise==0.0.5                     # exception raising linting
 flake8-use-fstring==1.4                 # format string checking
 flake8-noqa==1.3.0                      # validate noqa commands
diff --git a/dev-requirements/mypy.txt b/dev-requirements/mypy.txt
index 94f46f47..917d1d6e 100644
--- a/dev-requirements/mypy.txt
+++ b/dev-requirements/mypy.txt
@@ -1,1 +1,1 @@
-mypy==1.0.0
+mypy==1.0.1
diff --git a/dev-requirements/pyright.txt b/dev-requirements/pyright.txt
index 4fa2ba09..3bbd0ad3 100644
--- a/dev-requirements/pyright.txt
+++ b/dev-requirements/pyright.txt
@@ -1,1 +1,1 @@
-pyright==1.1.293
+pyright==1.1.296
diff --git a/dev-requirements/slotscheck.txt b/dev-requirements/slotscheck.txt
index 0ea5b04a..effa63a5 100644
--- a/dev-requirements/slotscheck.txt
+++ b/dev-requirements/slotscheck.txt
@@ -1,1 +1,1 @@
-slotscheck==0.16.4
+slotscheck==0.16.5
diff --git a/hikari/api/event_manager.py b/hikari/api/event_manager.py
index 189d3aa8..84012902 100644
--- a/hikari/api/event_manager.py
+++ b/hikari/api/event_manager.py
@@ -35,6 +35,8 @@
 if typing.TYPE_CHECKING:
     import types
 
+    from typing_extensions import Self
+
     from hikari.api import shard as gateway_shard
     from hikari.internal import data_binding
 
@@ -44,8 +46,6 @@
         [gateway_shard.GatewayShard, data_binding.JSONObject], typing.Coroutine[typing.Any, typing.Any, None]
     ]
 
-    _EventStreamT = typing.TypeVar("_EventStreamT")
-
 
 class EventStream(iterators.LazyIterator[base_events.EventT], abc.ABC):
     """A base abstract class for all event streamers.
@@ -110,10 +110,10 @@ def open(self) -> None:
 
     @abc.abstractmethod
     def filter(
-        self: _EventStreamT,
+        self,
         *predicates: typing.Union[typing.Tuple[str, typing.Any], typing.Callable[[base_events.EventT], bool]],
         **attrs: typing.Any,
-    ) -> _EventStreamT:
+    ) -> Self:
         """Filter the items by one or more conditions.
 
         Each condition is treated as a predicate, being called with each item
@@ -144,7 +144,7 @@ def filter(
         """
 
     @abc.abstractmethod
-    def __enter__(self: _EventStreamT) -> _EventStreamT:
+    def __enter__(self) -> Self:
         raise NotImplementedError
 
     @abc.abstractmethod
diff --git a/hikari/api/rest.py b/hikari/api/rest.py
index 4175d2c2..c9b07da5 100644
--- a/hikari/api/rest.py
+++ b/hikari/api/rest.py
@@ -265,7 +265,7 @@ async def edit_channel(
             If provided, the auto archive duration Discord's end user client
             should default to when creating threads in this channel.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         default_thread_rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
@@ -300,7 +300,7 @@ async def edit_channel(
             If provided, the new auto archive duration for this thread. This
             only applies to threads.
 
-            This should be either 60, 1440, 4320 or 10080 seconds, as of
+            This should be either 60, 1440, 4320 or 10080 minutes, as of
             writing.
         applied_tags : hikari.undefined.UndefinedOr[typing.Sequence[hikari.channels.ForumTag]]
             If provided, the new tags to apply to the thread. This only applies
@@ -4056,7 +4056,7 @@ async def create_guild_text_channel(
             If provided, the auto archive duration Discord's end user client
             should default to when creating threads in this channel.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         reason : hikari.undefined.UndefinedOr[str]
@@ -4134,7 +4134,7 @@ async def create_guild_news_channel(
             If provided, the auto archive duration Discord's end user client
             should default to when creating threads in this channel.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         reason : hikari.undefined.UndefinedOr[str]
@@ -4220,7 +4220,7 @@ async def create_guild_forum_channel(
             If provided, the auto archive duration Discord's end user client
             should default to when creating threads in this channel.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         default_thread_rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
@@ -4499,7 +4499,7 @@ async def create_message_thread(
         auto_archive_duration : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
             If provided, how long the thread should remain inactive until it's archived.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
@@ -4566,7 +4566,7 @@ async def create_thread(
         auto_archive_duration : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
             If provided, how long the thread should remain inactive until it's archived.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         invitable : undefined.UndefinedOr[bool]
@@ -4734,7 +4734,7 @@ async def create_forum_post(
         auto_archive_duration : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
             If provided, how long the post should remain inactive until it's archived.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
diff --git a/hikari/api/special_endpoints.py b/hikari/api/special_endpoints.py
index d86b038c..77bf6d3d 100644
--- a/hikari/api/special_endpoints.py
+++ b/hikari/api/special_endpoints.py
@@ -55,6 +55,8 @@
 if typing.TYPE_CHECKING:
     import types
 
+    from typing_extensions import Self
+
     from hikari import channels
     from hikari import colors
     from hikari import commands
@@ -74,8 +76,6 @@
     from hikari.interactions import base_interactions
     from hikari.internal import time
 
-    _T = typing.TypeVar("_T")
-
 _SelectMenuBuilderT = typing.TypeVar("_SelectMenuBuilderT", bound="SelectMenuBuilder[typing.Any]")
 _ContainerT = typing.TypeVar("_ContainerT")
 
@@ -564,7 +564,7 @@ def flags(self) -> typing.Union[undefined.UndefinedType, int, messages.MessageFl
         """
 
     @abc.abstractmethod
-    def set_flags(self: _T, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> _T:
+    def set_flags(self, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> Self:
         """Set message flags for this response.
 
         .. note::
@@ -593,7 +593,7 @@ def choices(self) -> typing.Sequence[commands.CommandChoice]:
         """Autocomplete choices."""
 
     @abc.abstractmethod
-    def set_choices(self: _T, choices: typing.Sequence[commands.CommandChoice], /) -> _T:
+    def set_choices(self, choices: typing.Sequence[commands.CommandChoice], /) -> Self:
         """Set autocomplete choices.
 
         Returns
@@ -689,7 +689,7 @@ def user_mentions(
         """
 
     @abc.abstractmethod
-    def clear_attachments(self: _T, /) -> _T:
+    def clear_attachments(self, /) -> Self:
         """Clear attachments for this response.
 
         This is only useful for message update responses, where you might want to
@@ -702,7 +702,7 @@ def clear_attachments(self: _T, /) -> _T:
         """
 
     @abc.abstractmethod
-    def add_attachment(self: _T, attachment: files.Resourceish, /) -> _T:
+    def add_attachment(self, attachment: files.Resourceish, /) -> Self:
         """Add an attachment to this response.
 
         Parameters
@@ -717,7 +717,7 @@ def add_attachment(self: _T, attachment: files.Resourceish, /) -> _T:
         """
 
     @abc.abstractmethod
-    def add_component(self: _T, component: ComponentBuilder, /) -> _T:
+    def add_component(self, component: ComponentBuilder, /) -> Self:
         """Add a component to this response.
 
         Parameters
@@ -732,7 +732,7 @@ def add_component(self: _T, component: ComponentBuilder, /) -> _T:
         """
 
     @abc.abstractmethod
-    def add_embed(self: _T, embed: embeds_.Embed, /) -> _T:
+    def add_embed(self, embed: embeds_.Embed, /) -> Self:
         """Add an embed to this response.
 
         Parameters
@@ -747,7 +747,7 @@ def add_embed(self: _T, embed: embeds_.Embed, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_content(self: _T, content: undefined.UndefinedOr[str], /) -> _T:
+    def set_content(self, content: undefined.UndefinedOr[str], /) -> Self:
         """Set the response's message content.
 
         Parameters
@@ -762,7 +762,7 @@ def set_content(self: _T, content: undefined.UndefinedOr[str], /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_flags(self: _T, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> _T:
+    def set_flags(self, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> Self:
         """Set message flags for this response.
 
         .. note::
@@ -781,7 +781,7 @@ def set_flags(self: _T, flags: typing.Union[undefined.UndefinedType, int, messag
         """
 
     @abc.abstractmethod
-    def set_tts(self: _T, tts: undefined.UndefinedOr[bool], /) -> _T:
+    def set_tts(self, tts: undefined.UndefinedOr[bool], /) -> Self:
         """Set whether this response should trigger text-to-speech processing.
 
         Parameters
@@ -796,7 +796,7 @@ def set_tts(self: _T, tts: undefined.UndefinedOr[bool], /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_mentions_everyone(self: _T, mentions: undefined.UndefinedOr[bool] = undefined.UNDEFINED, /) -> _T:
+    def set_mentions_everyone(self, mentions: undefined.UndefinedOr[bool] = undefined.UNDEFINED, /) -> Self:
         """Set whether this response should be able to mention @everyone/@here.
 
         Parameters
@@ -812,12 +812,12 @@ def set_mentions_everyone(self: _T, mentions: undefined.UndefinedOr[bool] = unde
 
     @abc.abstractmethod
     def set_role_mentions(
-        self: _T,
+        self,
         mentions: undefined.UndefinedOr[
             typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
         ] = undefined.UNDEFINED,
         /,
-    ) -> _T:
+    ) -> Self:
         """Set whether and what role mentions should be possible for this response.
 
         Parameters
@@ -835,12 +835,12 @@ def set_role_mentions(
 
     @abc.abstractmethod
     def set_user_mentions(
-        self: _T,
+        self,
         mentions: undefined.UndefinedOr[
             typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]
         ] = undefined.UNDEFINED,
         /,
-    ) -> _T:
+    ) -> Self:
         """Set whether and what user mentions should be possible for this response.
 
         Parameters
@@ -888,7 +888,7 @@ def components(self) -> undefined.UndefinedOr[typing.Sequence[ComponentBuilder]]
         """Sequence of component builders to send in this modal."""
 
     @abc.abstractmethod
-    def set_title(self: _T, title: str, /) -> _T:
+    def set_title(self, title: str, /) -> Self:
         """Set the title that will show up in the modal.
 
         Parameters
@@ -898,7 +898,7 @@ def set_title(self: _T, title: str, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_custom_id(self: _T, custom_id: str, /) -> _T:
+    def set_custom_id(self, custom_id: str, /) -> Self:
         """Set the developer set custom ID used for identifying interactions with this modal.
 
         Parameters
@@ -908,7 +908,7 @@ def set_custom_id(self: _T, custom_id: str, /) -> _T:
         """
 
     @abc.abstractmethod
-    def add_component(self: _T, component: ComponentBuilder, /) -> _T:
+    def add_component(self, component: ComponentBuilder, /) -> Self:
         """Add a component to this modal.
 
         Parameters
@@ -971,7 +971,7 @@ def name_localizations(self) -> typing.Mapping[typing.Union[locales.Locale, str]
         """Name localizations set for this command."""
 
     @abc.abstractmethod
-    def set_id(self: _T, id_: undefined.UndefinedOr[snowflakes.Snowflakeish], /) -> _T:
+    def set_id(self, id_: undefined.UndefinedOr[snowflakes.Snowflakeish], /) -> Self:
         """Set the ID of this command.
 
         Parameters
@@ -987,8 +987,8 @@ def set_id(self: _T, id_: undefined.UndefinedOr[snowflakes.Snowflakeish], /) ->
 
     @abc.abstractmethod
     def set_default_member_permissions(
-        self: _T, default_member_permissions: typing.Union[undefined.UndefinedType, int, permissions_.Permissions], /
-    ) -> _T:
+        self, default_member_permissions: typing.Union[undefined.UndefinedType, int, permissions_.Permissions], /
+    ) -> Self:
         """Set the member permissions necessary to utilize this command by default.
 
         Parameters
@@ -1006,7 +1006,7 @@ def set_default_member_permissions(
         """
 
     @abc.abstractmethod
-    def set_is_dm_enabled(self: _T, state: undefined.UndefinedOr[bool], /) -> _T:
+    def set_is_dm_enabled(self, state: undefined.UndefinedOr[bool], /) -> Self:
         """Set whether this command will be enabled in DMs with the bot.
 
         Parameters
@@ -1021,7 +1021,7 @@ def set_is_dm_enabled(self: _T, state: undefined.UndefinedOr[bool], /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_is_nsfw(self: _T, state: undefined.UndefinedOr[bool], /) -> _T:
+    def set_is_nsfw(self, state: undefined.UndefinedOr[bool], /) -> Self:
         """Set whether this command will be age-restricted.
 
         Parameters
@@ -1037,8 +1037,8 @@ def set_is_nsfw(self: _T, state: undefined.UndefinedOr[bool], /) -> _T:
 
     @abc.abstractmethod
     def set_name_localizations(
-        self: _T, name_localizations: typing.Mapping[typing.Union[locales.Locale, str], str], /
-    ) -> _T:
+        self, name_localizations: typing.Mapping[typing.Union[locales.Locale, str], str], /
+    ) -> Self:
         """Set the name localizations for this command.
 
         Parameters
@@ -1122,10 +1122,10 @@ def description_localizations(
 
     @abc.abstractmethod
     def set_description_localizations(
-        self: _T,
+        self,
         description_localizations: typing.Mapping[typing.Union[locales.Locale, str], str],
         /,
-    ) -> _T:
+    ) -> Self:
         """Set the localised descriptions for this command.
 
         Parameters
@@ -1145,7 +1145,7 @@ def options(self) -> typing.Sequence[commands.CommandOption]:
         """Sequence of up to 25 of the options set for this command."""
 
     @abc.abstractmethod
-    def add_option(self: _T, option: commands.CommandOption) -> _T:
+    def add_option(self, option: commands.CommandOption) -> Self:
         """Add an option to this command.
 
         .. note::
@@ -1243,6 +1243,11 @@ class ComponentBuilder(abc.ABC):
 
     __slots__: typing.Sequence[str] = ()
 
+    @property
+    @abc.abstractmethod
+    def type(self) -> typing.Union[int, components_.ComponentType]:
+        """Type of component this builder represents."""
+
     @abc.abstractmethod
     def build(self) -> typing.MutableMapping[str, typing.Any]:
         """Build a JSON object from this builder.
@@ -1259,6 +1264,11 @@ class ButtonBuilder(ComponentBuilder, abc.ABC, typing.Generic[_ContainerT]):
 
     __slots__: typing.Sequence[str] = ()
 
+    @property
+    @abc.abstractmethod
+    def type(self) -> typing.Literal[components_.ComponentType.BUTTON]:
+        """Type of component this builder represents."""
+
     @property
     @abc.abstractmethod
     def style(self) -> typing.Union[components_.ButtonStyle, int]:
@@ -1286,8 +1296,8 @@ def is_disabled(self) -> bool:
 
     @abc.abstractmethod
     def set_emoji(
-        self: _T, emoji: typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, undefined.UndefinedType], /
-    ) -> _T:
+        self, emoji: typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, undefined.UndefinedType], /
+    ) -> Self:
         """Set the emoji to display on this button.
 
         Parameters
@@ -1303,7 +1313,7 @@ def set_emoji(
         """
 
     @abc.abstractmethod
-    def set_label(self: _T, label: undefined.UndefinedOr[str], /) -> _T:
+    def set_label(self, label: undefined.UndefinedOr[str], /) -> Self:
         """Set the text label which should be displayed on this button.
 
         Parameters
@@ -1320,7 +1330,7 @@ def set_label(self: _T, label: undefined.UndefinedOr[str], /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_is_disabled(self: _T, state: bool, /) -> _T:
+    def set_is_disabled(self, state: bool, /) -> Self:
         """Set whether this button should be disabled.
 
         Parameters
@@ -1369,7 +1379,7 @@ def custom_id(self) -> str:
         """Developer set custom ID used for identifying interactions with this button."""
 
 
-class SelectOptionBuilder(ComponentBuilder, abc.ABC, typing.Generic[_SelectMenuBuilderT]):
+class SelectOptionBuilder(abc.ABC, typing.Generic[_SelectMenuBuilderT]):
     """Builder class for select menu options."""
 
     __slots__: typing.Sequence[str] = ()
@@ -1400,7 +1410,7 @@ def is_default(self) -> bool:
         """Whether this option should be marked as selected by default."""
 
     @abc.abstractmethod
-    def set_description(self: _T, value: undefined.UndefinedOr[str], /) -> _T:
+    def set_description(self, value: undefined.UndefinedOr[str], /) -> Self:
         """Set the option's description.
 
         Parameters
@@ -1417,8 +1427,8 @@ def set_description(self: _T, value: undefined.UndefinedOr[str], /) -> _T:
 
     @abc.abstractmethod
     def set_emoji(
-        self: _T, emoji: typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, undefined.UndefinedType], /
-    ) -> _T:
+        self, emoji: typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, undefined.UndefinedType], /
+    ) -> Self:
         """Set the emoji to display on this option.
 
         Parameters
@@ -1434,7 +1444,7 @@ def set_emoji(
         """
 
     @abc.abstractmethod
-    def set_is_default(self: _T, state: bool, /) -> _T:
+    def set_is_default(self, state: bool, /) -> Self:
         """Set whether this option should be selected by default.
 
         Parameters
@@ -1460,6 +1470,16 @@ def add_to_menu(self) -> _SelectMenuBuilderT:
             The menu component that owns this button.
         """
 
+    @abc.abstractmethod
+    def build(self) -> typing.MutableMapping[str, typing.Any]:
+        """Build a JSON object from this builder.
+
+        Returns
+        -------
+        typing.MutableMapping[str, typing.Any]
+            The built json object representation of this builder.
+        """
+
 
 class SelectMenuBuilder(ComponentBuilder, abc.ABC, typing.Generic[_ContainerT]):
     """Builder class for a select menu."""
@@ -1502,7 +1522,7 @@ def max_values(self) -> int:
         """
 
     @abc.abstractmethod
-    def set_is_disabled(self: _T, state: bool, /) -> _T:
+    def set_is_disabled(self, state: bool, /) -> Self:
         """Set whether this option is disabled.
 
         Defaults to `False`.
@@ -1519,7 +1539,7 @@ def set_is_disabled(self: _T, state: bool, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_placeholder(self: _T, value: undefined.UndefinedOr[str], /) -> _T:
+    def set_placeholder(self, value: undefined.UndefinedOr[str], /) -> Self:
         """Set place-holder text to be shown when no option is selected.
 
         Parameters
@@ -1535,7 +1555,7 @@ def set_placeholder(self: _T, value: undefined.UndefinedOr[str], /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_min_values(self: _T, value: int, /) -> _T:
+    def set_min_values(self, value: int, /) -> Self:
         """Set the minimum amount of options which need to be selected for this menu.
 
         .. note::
@@ -1554,7 +1574,7 @@ def set_min_values(self: _T, value: int, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_max_values(self: _T, value: int, /) -> _T:
+    def set_max_values(self, value: int, /) -> Self:
         """Set the maximum amount of options which can be selected for this menu.
 
         .. note::
@@ -1590,11 +1610,11 @@ class TextSelectMenuBuilder(SelectMenuBuilder[_ContainerT], abc.ABC, typing.Gene
 
     @property
     @abc.abstractmethod
-    def options(self: _SelectMenuBuilderT) -> typing.Sequence[SelectOptionBuilder[_SelectMenuBuilderT]]:
+    def options(self) -> typing.Sequence[SelectOptionBuilder[Self]]:
         """Sequence of the options set for this select menu."""
 
     @abc.abstractmethod
-    def add_option(self: _SelectMenuBuilderT, label: str, value: str, /) -> SelectOptionBuilder[_SelectMenuBuilderT]:
+    def add_option(self, label: str, value: str, /) -> SelectOptionBuilder[Self]:
         """Add an option to this menu.
 
         .. note::
@@ -1626,7 +1646,7 @@ def channel_types(self) -> typing.Sequence[channels.ChannelType]:
         """The channel types that can be selected in this menu."""
 
     @abc.abstractmethod
-    def set_channel_types(self: _T, value: typing.Sequence[channels.ChannelType], /) -> _T:
+    def set_channel_types(self, value: typing.Sequence[channels.ChannelType], /) -> Self:
         """Set the valid channel types for this menu.
 
         Parameters
@@ -1646,6 +1666,11 @@ class TextInputBuilder(ComponentBuilder, abc.ABC, typing.Generic[_ContainerT]):
 
     __slots__: typing.Sequence[str] = ()
 
+    @property
+    @abc.abstractmethod
+    def type(self) -> typing.Literal[components_.ComponentType.TEXT_INPUT]:
+        """Type of component this builder represents."""
+
     @property
     @abc.abstractmethod
     def custom_id(self) -> str:
@@ -1692,7 +1717,7 @@ def max_length(self) -> undefined.UndefinedOr[int]:
         """Maximum length the text should have."""
 
     @abc.abstractmethod
-    def set_style(self: _T, style: typing.Union[components_.TextInputStyle, int], /) -> _T:
+    def set_style(self, style: typing.Union[components_.TextInputStyle, int], /) -> Self:
         """Set the style to use for the text input.
 
         Parameters
@@ -1707,7 +1732,7 @@ def set_style(self: _T, style: typing.Union[components_.TextInputStyle, int], /)
         """
 
     @abc.abstractmethod
-    def set_custom_id(self: _T, custom_id: str, /) -> _T:
+    def set_custom_id(self, custom_id: str, /) -> Self:
         """Set the developer set custom ID used for identifying this text input.
 
         Parameters
@@ -1722,7 +1747,7 @@ def set_custom_id(self: _T, custom_id: str, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_label(self: _T, label: str, /) -> _T:
+    def set_label(self, label: str, /) -> Self:
         """Set the label above this text input.
 
         Parameters
@@ -1737,7 +1762,7 @@ def set_label(self: _T, label: str, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_placeholder(self: _T, placeholder: str, /) -> _T:
+    def set_placeholder(self, placeholder: str, /) -> Self:
         """Set the placeholder text for when the text input is empty.
 
         Parameters
@@ -1752,7 +1777,7 @@ def set_placeholder(self: _T, placeholder: str, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_value(self: _T, value: str, /) -> _T:
+    def set_value(self, value: str, /) -> Self:
         """Pre-filled text that will be sent if the user does not write anything.
 
         Parameters
@@ -1767,7 +1792,7 @@ def set_value(self: _T, value: str, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_required(self: _T, required: bool, /) -> _T:
+    def set_required(self, required: bool, /) -> Self:
         """Set whether this text input is required to be filled-in.
 
         Parameters
@@ -1782,7 +1807,7 @@ def set_required(self: _T, required: bool, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_min_length(self: _T, min_length: int, /) -> _T:
+    def set_min_length(self, min_length: int, /) -> Self:
         """Set the minimum length the text should have.
 
         Parameters
@@ -1797,7 +1822,7 @@ def set_min_length(self: _T, min_length: int, /) -> _T:
         """
 
     @abc.abstractmethod
-    def set_max_length(self: _T, max_length: int, /) -> _T:
+    def set_max_length(self, max_length: int, /) -> Self:
         """Set the maximum length the text should have.
 
         Parameters
@@ -1827,17 +1852,18 @@ class MessageActionRowBuilder(ComponentBuilder, abc.ABC):
 
     __slots__: typing.Sequence[str] = ()
 
+    @property
+    @abc.abstractmethod
+    def type(self) -> typing.Literal[components_.ComponentType.ACTION_ROW]:
+        """Type of component this builder represents."""
+
     @property
     @abc.abstractmethod
     def components(self) -> typing.Sequence[ComponentBuilder]:
         """Sequence of the component builders registered within this action row."""
 
     @abc.abstractmethod
-    def add_component(
-        self: _T,
-        component: ComponentBuilder,
-        /,
-    ) -> _T:
+    def add_component(self, component: ComponentBuilder, /) -> Self:
         """Add a component to this action row builder.
 
         .. warning::
@@ -1859,28 +1885,28 @@ def add_component(
     @typing.overload
     @abc.abstractmethod
     def add_button(
-        self: _T, style: components_.InteractiveButtonTypesT, custom_id: str, /
-    ) -> InteractiveButtonBuilder[_T]:
+        self, style: components_.InteractiveButtonTypesT, custom_id: str, /
+    ) -> InteractiveButtonBuilder[Self]:
         ...
 
     @typing.overload
     @abc.abstractmethod
     def add_button(
-        self: _T, style: typing.Literal[components_.ButtonStyle.LINK, 5], url: str, /
-    ) -> LinkButtonBuilder[_T]:
+        self, style: typing.Literal[components_.ButtonStyle.LINK, 5], url: str, /
+    ) -> LinkButtonBuilder[Self]:
         ...
 
     @typing.overload
     @abc.abstractmethod
     def add_button(
-        self: _T, style: typing.Union[int, components_.ButtonStyle], url_or_custom_id: str, /
-    ) -> typing.Union[LinkButtonBuilder[_T], InteractiveButtonBuilder[_T]]:
+        self, style: typing.Union[int, components_.ButtonStyle], url_or_custom_id: str, /
+    ) -> typing.Union[LinkButtonBuilder[Self], InteractiveButtonBuilder[Self]]:
         ...
 
     @abc.abstractmethod
     def add_button(
-        self: _T, style: typing.Union[int, components_.ButtonStyle], url_or_custom_id: str, /
-    ) -> typing.Union[LinkButtonBuilder[_T], InteractiveButtonBuilder[_T]]:
+        self, style: typing.Union[int, components_.ButtonStyle], url_or_custom_id: str, /
+    ) -> typing.Union[LinkButtonBuilder[Self], InteractiveButtonBuilder[Self]]:
         """Add a button component to this action row builder.
 
         Parameters
@@ -1905,51 +1931,51 @@ def add_button(
     @typing.overload  # Deprecated overload
     @abc.abstractmethod
     def add_select_menu(
-        self: _T,
+        self,
         custom_id: str,
         /,
-    ) -> TextSelectMenuBuilder[_T]:
+    ) -> TextSelectMenuBuilder[Self]:
         ...
 
     @typing.overload
     @abc.abstractmethod
     def add_select_menu(
-        self: _T,
+        self,
         type_: typing.Literal[components_.ComponentType.TEXT_SELECT_MENU, 3],
         custom_id: str,
         /,
-    ) -> TextSelectMenuBuilder[_T]:
+    ) -> TextSelectMenuBuilder[Self]:
         ...
 
     @typing.overload
     @abc.abstractmethod
     def add_select_menu(
-        self: _T,
+        self,
         type_: typing.Literal[components_.ComponentType.CHANNEL_SELECT_MENU, 8],
         custom_id: str,
         /,
-    ) -> ChannelSelectMenuBuilder[_T]:
+    ) -> ChannelSelectMenuBuilder[Self]:
         ...
 
     @typing.overload
     @abc.abstractmethod
     def add_select_menu(
-        self: _T,
+        self,
         type_: typing.Union[components_.ComponentType, int],
         custom_id: str,
         /,
-    ) -> SelectMenuBuilder[_T]:
+    ) -> SelectMenuBuilder[Self]:
         ...
 
     @abc.abstractmethod
     def add_select_menu(
-        self: _T,
+        self,
         type_: typing.Union[components_.ComponentType, int, str],
         # These have default during the deprecation period for backwards compatibility, as custom_id
         # used to come first
         custom_id: str = "",
         /,
-    ) -> SelectMenuBuilder[_T]:
+    ) -> SelectMenuBuilder[Self]:
         """Add a select menu component to this action row builder.
 
         .. deprecated:: 2.0.0.dev116
@@ -1982,6 +2008,11 @@ class ModalActionRowBuilder(ComponentBuilder, abc.ABC):
 
     __slots__: typing.Sequence[str] = ()
 
+    @property
+    @abc.abstractmethod
+    def type(self) -> typing.Literal[components_.ComponentType.ACTION_ROW]:
+        """Type of component this builder represents."""
+
     @property
     @abc.abstractmethod
     def components(self) -> typing.Sequence[ComponentBuilder]:
@@ -1989,10 +2020,10 @@ def components(self) -> typing.Sequence[ComponentBuilder]:
 
     @abc.abstractmethod
     def add_component(
-        self: _T,
+        self,
         component: ComponentBuilder,
         /,
-    ) -> _T:
+    ) -> Self:
         """Add a component to this action row builder.
 
         .. warning::
@@ -2013,10 +2044,10 @@ def add_component(
 
     @abc.abstractmethod
     def add_text_input(
-        self: _T,
+        self,
         custom_id: str,
         label: str,
-    ) -> TextInputBuilder[_T]:
+    ) -> TextInputBuilder[Self]:
         """Add a text input component to this action row builder.
 
         Parameters
diff --git a/hikari/api/voice.py b/hikari/api/voice.py
index d158ff59..f8985fb6 100644
--- a/hikari/api/voice.py
+++ b/hikari/api/voice.py
@@ -31,12 +31,12 @@
 from hikari.events import voice_events
 
 if typing.TYPE_CHECKING:
+    from typing_extensions import Self
+
     from hikari import channels
     from hikari import guilds
     from hikari import snowflakes
 
-    _T = typing.TypeVar("_T")
-
     _VoiceConnectionT = typing.TypeVar("_VoiceConnectionT", bound="VoiceConnection")
 
 
@@ -149,18 +149,18 @@ class VoiceConnection(abc.ABC):
     @classmethod
     @abc.abstractmethod
     async def initialize(
-        cls: typing.Type[_T],
+        cls,
         channel_id: snowflakes.Snowflake,
         endpoint: str,
         guild_id: snowflakes.Snowflake,
-        on_close: typing.Callable[[_T], typing.Awaitable[None]],
+        on_close: typing.Callable[[Self], typing.Awaitable[None]],
         owner: VoiceComponent,
         session_id: str,
         shard_id: int,
         token: str,
         user_id: snowflakes.Snowflake,
         **kwargs: typing.Any,
-    ) -> _T:
+    ) -> Self:
         """Initialize and connect the voice connection.
 
         Parameters
diff --git a/hikari/channels.py b/hikari/channels.py
index 1581662f..baa02f4e 100644
--- a/hikari/channels.py
+++ b/hikari/channels.py
@@ -1037,7 +1037,7 @@ async def edit(
             If provided, the auto archive duration Discord's end user client
             should default to when creating threads in this channel.
 
-            This should be either 60, 1440, 4320 or 10080 seconds, as of
+            This should be either 60, 1440, 4320 or 10080 minutes, as of
             writing.
         flags : hikari.undefined.UndefinedOr[ChannelFlag]
             If provided, the new channel flags to use for the channel. This can
@@ -1050,7 +1050,7 @@ async def edit(
             If provided, the new auto archive duration for this thread. This
             only applies to threads.
 
-            This should be either 60, 1440, 4320 or 10080 seconds, as of
+            This should be either 60, 1440, 4320 or 10080 minutes, as of
             writing.
         locked : hikari.undefined.UndefinedOr[bool]
             If provided, the new locked state for the thread. This only applies
diff --git a/hikari/commands.py b/hikari/commands.py
index 3a2cb76c..41c2c3a7 100644
--- a/hikari/commands.py
+++ b/hikari/commands.py
@@ -254,9 +254,9 @@ class PartialCommand(snowflakes.Unique):
     """Auto-incrementing version identifier updated during substantial record changes."""
 
     name_localizations: typing.Mapping[typing.Union[locales.Locale, str], str] = attr.field(
-        eq=False, factory=dict, hash=False, repr=False
+        eq=False, hash=False, repr=False
     )
-    """A mapping of name localizations for this option."""
+    """A mapping of name localizations for this command."""
 
     async def fetch_self(self) -> PartialCommand:
         """Fetch an up-to-date version of this command object.
@@ -447,7 +447,7 @@ class SlashCommand(PartialCommand):
     description_localizations: typing.Mapping[typing.Union[locales.Locale, str], str] = attr.field(
         eq=False, hash=False, repr=False
     )
-    """A set of description localizations for this command"""
+    """A set of description localizations for this command."""
 
     options: typing.Optional[typing.Sequence[CommandOption]] = attr.field(eq=False, hash=False, repr=False)
     """Sequence of up to (and including) 25 of the options for this command."""
diff --git a/hikari/guilds.py b/hikari/guilds.py
index ddbf3438..34893db9 100644
--- a/hikari/guilds.py
+++ b/hikari/guilds.py
@@ -2113,7 +2113,7 @@ async def create_forum_channel(
             If provided, the auto archive duration Discord's end user client
             should default to when creating threads in this channel.
 
-            This should be either 60, 1440, 4320 or 10080 seconds and, as of
+            This should be either 60, 1440, 4320 or 10080 minutes and, as of
             writing, ignores the parent channel's set default_auto_archive_duration
             when passed as `hikari.undefined.UNDEFINED`.
         default_thread_rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish]
diff --git a/hikari/impl/buckets.py b/hikari/impl/buckets.py
index 807e5ae8..52ee79bc 100644
--- a/hikari/impl/buckets.py
+++ b/hikari/impl/buckets.py
@@ -385,7 +385,6 @@ class RESTBucketManager:
         "_routes_to_hashes",
         "_real_hashes_to_buckets",
         "_global_ratelimit",
-        "_closed_event",
         "_gc_task",
         "_max_rate_limit",
     )
@@ -393,7 +392,6 @@ class RESTBucketManager:
     def __init__(self, max_rate_limit: float) -> None:
         self._routes_to_hashes: typing.Dict[routes.Route, str] = {}
         self._real_hashes_to_buckets: typing.Dict[str, RESTBucket] = {}
-        self._closed_event: typing.Optional[asyncio.Event] = None
         self._gc_task: typing.Optional[asyncio.Task[None]] = None
         self._max_rate_limit = max_rate_limit
         self._global_ratelimit = rate_limits.ManualRateLimiter()
@@ -405,7 +403,7 @@ def max_rate_limit(self) -> float:
     @property
     def is_alive(self) -> bool:
         """Whether the component is alive."""
-        return self._closed_event is not None
+        return self._gc_task is not None
 
     def start(self, poll_period: float = 20.0, expire_after: float = 10.0) -> None:
         """Start this ratelimiter up.
@@ -426,22 +424,19 @@ def start(self, poll_period: float = 20.0, expire_after: float = 10.0) -> None:
             result. Using `0` will make the bucket get garbage collected as soon
             as the rate limit has reset. Defaults to `10` seconds.
         """
-        if self._closed_event:
+        if self._gc_task:
             raise errors.ComponentStateConflictError("Cannot start an active bucket manager")
 
         # Assert is in running loop
         asyncio.get_running_loop()
 
-        self._closed_event = asyncio.Event()
         self._gc_task = asyncio.create_task(self._gc(poll_period, expire_after))
 
-    def close(self) -> None:
+    async def close(self) -> None:
         """Close the garbage collector and kill any tasks waiting on ratelimits."""
-        if not self._closed_event:
+        if not self._gc_task:
             raise errors.ComponentStateConflictError("Cannot interact with an inactive bucket manager")
 
-        assert self._closed_event is not None
-
         for bucket in self._real_hashes_to_buckets.values():
             bucket.close()
 
@@ -449,49 +444,24 @@ def close(self) -> None:
         self._real_hashes_to_buckets.clear()
         self._routes_to_hashes.clear()
 
-        if self._gc_task is not None:
-            self._gc_task.cancel()
-            self._gc_task = None
-
-        self._closed_event.set()
-        self._closed_event = None
-
-    async def _gc(self, poll_period: float, expire_after: float) -> None:
-        """Run the garbage collector loop.
+        self._gc_task.cancel()
 
-        This is designed to run in the background and manage removing unused
-        route references from the rate-limiter collection to save memory.
+        try:
+            await self._gc_task
+        except asyncio.CancelledError:
+            pass
 
-        This will run forever until `RESTBucketManager.closed_event` is set.
-        This will invoke `RESTBucketManager.do_gc_pass` periodically.
+        self._gc_task = None
 
-        .. warning::
-            You generally have no need to invoke this directly. Use
-            `RESTBucketManager.start` and `RESTBucketManager.close` to control
-            this instead.
-
-        Parameters
-        ----------
-        poll_period : float
-            The period to poll at.
-        expire_after : float
-            Time after which the last `reset_at` was hit for a bucket to
-            remove it. Higher values will retain unneeded ratelimit info for
-            longer, but may produce more effective ratelimiting logic as a
-            result. Using `0` will make the bucket get garbage collected as soon
-            as the rate limit has reset.
-        """
+    async def _gc(self, poll_period: float, expire_after: float) -> None:
         # Prevent filling memory increasingly until we run out by removing dead buckets every 20s
         # Allocations are somewhat cheap if we only do them every so-many seconds, after all.
         _LOGGER.log(ux.TRACE, "rate limit garbage collector started")
 
-        assert self._closed_event is not None
-        while not self._closed_event.is_set():
-            try:
-                await asyncio.wait_for(self._closed_event.wait(), timeout=poll_period)
-            except asyncio.TimeoutError:
-                _LOGGER.log(ux.TRACE, "performing rate limit garbage collection pass")
-                self._purge_stale_buckets(expire_after)
+        while True:
+            await asyncio.sleep(poll_period)
+            _LOGGER.log(ux.TRACE, "performing rate limit garbage collection pass")
+            self._purge_stale_buckets(expire_after)
 
     def _purge_stale_buckets(self, expire_after: float) -> None:
         buckets_to_purge: typing.List[str] = []
@@ -550,7 +520,7 @@ def acquire_bucket(
         typing.AsyncContextManager
             The context manager to use during the duration of the request.
         """
-        if not self._closed_event:
+        if not self._gc_task:
             raise errors.ComponentStateConflictError("Cannot interact with an inactive bucket manager")
 
         authentication_hash = _create_authentication_hash(authentication)
@@ -600,7 +570,7 @@ def update_rate_limits(
         reset_after : float
             The `X-RateLimit-Reset-After` header cast to a `float`.
         """
-        if not self._closed_event:
+        if not self._gc_task:
             raise errors.ComponentStateConflictError("Cannot interact with an inactive bucket manager")
 
         self._routes_to_hashes[compiled_route.route] = bucket_header
diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py
index fb753048..199252e3 100644
--- a/hikari/impl/entity_factory.py
+++ b/hikari/impl/entity_factory.py
@@ -2368,7 +2368,7 @@ def deserialize_partial_interaction(self, payload: data_binding.JSONObject) -> b
     def _deserialize_interaction_command_option(
         self, payload: data_binding.JSONObject
     ) -> command_interactions.CommandInteractionOption:
-        suboptions: typing.Optional[typing.List[command_interactions.CommandInteractionOption]] = None
+        suboptions: typing.Optional[typing.Sequence[command_interactions.CommandInteractionOption]] = None
         if raw_suboptions := payload.get("options"):
             suboptions = [self._deserialize_interaction_command_option(suboption) for suboption in raw_suboptions]
 
@@ -2381,14 +2381,14 @@ def _deserialize_interaction_command_option(
             name=payload["name"],
             type=option_type,
             value=value,
-            options=suboptions,
+            options=suboptions,  # type: ignore[arg-type]  # MyPy gets the type equality wrong here.
         )
 
     def _deserialize_autocomplete_interaction_option(
         self,
         payload: data_binding.JSONObject,
     ) -> command_interactions.AutocompleteInteractionOption:
-        suboptions: typing.Optional[typing.List[command_interactions.AutocompleteInteractionOption]] = None
+        suboptions: typing.Optional[typing.Sequence[command_interactions.AutocompleteInteractionOption]] = None
         if raw_suboptions := payload.get("options"):
             suboptions = [self._deserialize_autocomplete_interaction_option(suboption) for suboption in raw_suboptions]
 
@@ -2403,7 +2403,7 @@ def _deserialize_autocomplete_interaction_option(
             name=payload["name"],
             type=option_type,
             value=value,
-            options=suboptions,
+            options=suboptions,  # type: ignore[arg-type]  # MyPy gets the type equality wrong here.
             is_focused=is_focused,
         )
 
diff --git a/hikari/impl/event_manager_base.py b/hikari/impl/event_manager_base.py
index 12cf8d42..9e7f3e24 100644
--- a/hikari/impl/event_manager_base.py
+++ b/hikari/impl/event_manager_base.py
@@ -50,6 +50,8 @@
 from hikari.internal import ux
 
 if typing.TYPE_CHECKING:
+    from typing_extensions import Self
+
     from hikari import intents as intents_
     from hikari.api import event_factory as event_factory_
     from hikari.api import shard as gateway_shard
@@ -73,8 +75,6 @@
         typing.Coroutine[typing.Any, typing.Any, None],
     ]
 
-    _EventStreamT = typing.TypeVar("_EventStreamT", bound="EventStream[typing.Any]")
-
 
 if sys.version_info >= (3, 10):
     # We can use types.UnionType on 3.10+
@@ -162,7 +162,7 @@ def __init__(
         # The registered wrapping function for the weak ref to this class's _listener method.
         self._timeout = timeout
 
-    def __enter__(self: _EventStreamT) -> _EventStreamT:
+    def __enter__(self) -> Self:
         self.open()
         return self
 
@@ -229,10 +229,10 @@ def close(self) -> None:
         self._active = False
 
     def filter(
-        self: _EventStreamT,
+        self,
         *predicates: typing.Union[typing.Tuple[str, typing.Any], typing.Callable[[base_events.EventT], bool]],
         **attrs: typing.Any,
-    ) -> _EventStreamT:
+    ) -> Self:
         filter_ = self._map_predicates_and_attr_getters("filter", *predicates, **attrs)
         if self._active:
             self._queue = [entry for entry in self._queue if filter_(entry)]
diff --git a/hikari/impl/rest.py b/hikari/impl/rest.py
index e21a8042..5e1b42d3 100644
--- a/hikari/impl/rest.py
+++ b/hikari/impl/rest.py
@@ -352,7 +352,7 @@ async def close(self) -> None:
             raise errors.ComponentStateConflictError("Rest app is not running")
 
         await self._client_session.close()
-        self._bucket_manager.close()
+        await self._bucket_manager.close()
 
     @typing.overload
     def acquire(self, token: typing.Optional[rest_api.TokenStrategy] = None) -> RESTClientImpl:
@@ -645,7 +645,7 @@ async def close(self) -> None:
             self._client_session = None
 
         if self._bucket_manager_owner:
-            self._bucket_manager.close()
+            await self._bucket_manager.close()
 
     def start(self) -> None:
         """Start the HTTP client.
diff --git a/hikari/impl/rest_bot.py b/hikari/impl/rest_bot.py
index 8a56ed90..39991954 100644
--- a/hikari/impl/rest_bot.py
+++ b/hikari/impl/rest_bot.py
@@ -30,6 +30,7 @@
 import sys
 import typing
 
+from hikari import applications
 from hikari import errors
 from hikari import traits
 from hikari.api import interaction_server as interaction_server_
@@ -47,7 +48,6 @@
     import socket as socket_
     import ssl
 
-    from hikari import applications
     from hikari.api import entity_factory as entity_factory_api
     from hikari.api import rest as rest_api
     from hikari.api import special_endpoints
@@ -78,7 +78,8 @@ class RESTBot(traits.RESTBotAware, interaction_server_.InteractionServer):
         The bot or bearer token.
     token_type : typing.Union[str, hikari.applications.TokenType, None]
         The type of token in use. This should only be passed when `str`
-        is passed for `token`, can be `"Bot"` or `"Bearer"`.
+        is passed for `token`, can be `"Bot"` or `"Bearer"` and defaults
+        to `"Bot".
 
         This should be left as `None` when `hikari.api.rest.TokenStrategy`
         is passed for `token`.
@@ -259,7 +260,7 @@ def __init__(
     def __init__(
         self,
         token: str,
-        token_type: typing.Union[str, applications.TokenType],
+        token_type: typing.Union[str, applications.TokenType] = applications.TokenType.BOT,
         public_key: typing.Union[bytes, str, None] = None,
         *,
         allow_color: bool = True,
@@ -300,6 +301,9 @@ def __init__(
         if isinstance(token, str):
             token = token.strip()
 
+            if token_type is None:
+                token_type = applications.TokenType.BOT
+
         # Beautification and logging
         ux.init_logging(logs, allow_color, force_color)
         self.print_banner(banner, allow_color, force_color)
diff --git a/hikari/impl/special_endpoints.py b/hikari/impl/special_endpoints.py
index e03b22b1..92974d74 100644
--- a/hikari/impl/special_endpoints.py
+++ b/hikari/impl/special_endpoints.py
@@ -38,6 +38,8 @@
     "InteractiveButtonBuilder",
     "LinkButtonBuilder",
     "SelectMenuBuilder",
+    "ChannelSelectMenuBuilder",
+    "TextSelectMenuBuilder",
     "TextInputBuilder",
     "InteractionModalBuilder",
     "MessageActionRowBuilder",
@@ -73,6 +75,8 @@
     import concurrent.futures
     import types
 
+    from typing_extensions import Self
+
     from hikari import applications
     from hikari import audit_logs
     from hikari import colors
@@ -86,24 +90,7 @@
     from hikari.api import rest as rest_api
 
     _T = typing.TypeVar("_T")
-    _CommandBuilderT = typing.TypeVar("_CommandBuilderT", bound="CommandBuilder")
-    _SlashCommandBuilderT = typing.TypeVar("_SlashCommandBuilderT", bound="SlashCommandBuilder")
-    _InteractionMessageBuilderT = typing.TypeVar("_InteractionMessageBuilderT", bound="InteractionMessageBuilder")
-    _InteractionDeferredBuilderT = typing.TypeVar("_InteractionDeferredBuilderT", bound="InteractionDeferredBuilder")
-    _InteractionAutocompleteBuilderT = typing.TypeVar(
-        "_InteractionAutocompleteBuilderT", bound="InteractionAutocompleteBuilder"
-    )
-    _InteractionModalBuilderT = typing.TypeVar("_InteractionModalBuilderT", bound="InteractionModalBuilder")
-    _MessageActionRowBuilderT = typing.TypeVar("_MessageActionRowBuilderT", bound="MessageActionRowBuilder")
-    _ModalActionRowBuilderT = typing.TypeVar("_ModalActionRowBuilderT", bound="ModalActionRowBuilder")
-    _ButtonBuilderT = typing.TypeVar("_ButtonBuilderT", bound="_ButtonBuilder[typing.Any]")
-    _SelectOptionBuilderT = typing.TypeVar("_SelectOptionBuilderT", bound="_SelectOptionBuilder[typing.Any]")
-    _SelectMenuBuilderT = typing.TypeVar("_SelectMenuBuilderT", bound="SelectMenuBuilder[typing.Any]")
     _TextSelectMenuBuilderT = typing.TypeVar("_TextSelectMenuBuilderT", bound="TextSelectMenuBuilder[typing.Any]")
-    _ChannelSelectMenuBuilderT = typing.TypeVar(
-        "_ChannelSelectMenuBuilderT", bound="ChannelSelectMenuBuilder[typing.Any]"
-    )
-    _TextInputBuilderT = typing.TypeVar("_TextInputBuilderT", bound="TextInputBuilder[typing.Any]")
 
     class _RequestCallSig(typing.Protocol):
         async def __call__(
@@ -131,7 +118,7 @@ def __call__(
 
     # Hack around used to avoid recursive generic types leading to type checker issues in builders
     class _ContainerProto(typing.Protocol):
-        def add_component(self: _T, component: special_endpoints.ComponentBuilder, /) -> _T:
+        def add_component(self, component: special_endpoints.ComponentBuilder, /) -> Self:
             raise NotImplementedError
 
 
@@ -922,9 +909,7 @@ def type(self) -> typing.Literal[base_interactions.ResponseType.AUTOCOMPLETE]:
     def choices(self) -> typing.Sequence[commands.CommandChoice]:
         return self._choices
 
-    def set_choices(
-        self: _InteractionAutocompleteBuilderT, choices: typing.Sequence[commands.CommandChoice], /
-    ) -> _InteractionAutocompleteBuilderT:
+    def set_choices(self, choices: typing.Sequence[commands.CommandChoice], /) -> Self:
         """Set autocomplete choices.
 
         Returns
@@ -972,9 +957,7 @@ def type(self) -> base_interactions.DeferredResponseTypesT:
     def flags(self) -> typing.Union[undefined.UndefinedType, int, messages.MessageFlag]:
         return self._flags
 
-    def set_flags(
-        self: _InteractionDeferredBuilderT, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /
-    ) -> _InteractionDeferredBuilderT:
+    def set_flags(self, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> Self:
         self._flags = flags
         return self
 
@@ -1082,74 +1065,64 @@ def user_mentions(
     ) -> undefined.UndefinedOr[typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]]:
         return self._user_mentions
 
-    def clear_attachments(self: _InteractionMessageBuilderT, /) -> _InteractionMessageBuilderT:
+    def clear_attachments(self, /) -> Self:
         self._attachments = None
         return self
 
-    def add_attachment(
-        self: _InteractionMessageBuilderT, attachment: files.Resourceish, /
-    ) -> _InteractionMessageBuilderT:
+    def add_attachment(self, attachment: files.Resourceish, /) -> Self:
         if not self._attachments:
             self._attachments = []
 
         self._attachments.append(attachment)
         return self
 
-    def add_component(
-        self: _InteractionMessageBuilderT, component: special_endpoints.ComponentBuilder, /
-    ) -> _InteractionMessageBuilderT:
+    def add_component(self, component: special_endpoints.ComponentBuilder, /) -> Self:
         if self._components is undefined.UNDEFINED:
             self._components = []
 
         self._components.append(component)
         return self
 
-    def add_embed(self: _InteractionMessageBuilderT, embed: embeds_.Embed, /) -> _InteractionMessageBuilderT:
+    def add_embed(self, embed: embeds_.Embed, /) -> Self:
         if self._embeds is undefined.UNDEFINED:
             self._embeds = []
 
         self._embeds.append(embed)
         return self
 
-    def set_content(
-        self: _InteractionMessageBuilderT, content: undefined.UndefinedOr[str], /
-    ) -> _InteractionMessageBuilderT:
+    def set_content(self, content: undefined.UndefinedOr[str], /) -> Self:
         self._content = str(content) if content is not undefined.UNDEFINED else undefined.UNDEFINED
         return self
 
-    def set_flags(
-        self: _InteractionMessageBuilderT, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /
-    ) -> _InteractionMessageBuilderT:
+    def set_flags(self, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> Self:
         self._flags = flags
         return self
 
-    def set_tts(self: _InteractionMessageBuilderT, tts: undefined.UndefinedOr[bool], /) -> _InteractionMessageBuilderT:
+    def set_tts(self, tts: undefined.UndefinedOr[bool], /) -> Self:
         self._is_tts = tts
         return self
 
-    def set_mentions_everyone(
-        self: _InteractionMessageBuilderT, state: undefined.UndefinedOr[bool] = undefined.UNDEFINED, /
-    ) -> _InteractionMessageBuilderT:
+    def set_mentions_everyone(self, state: undefined.UndefinedOr[bool] = undefined.UNDEFINED, /) -> Self:
         self._mentions_everyone = state
         return self
 
     def set_role_mentions(
-        self: _InteractionMessageBuilderT,
+        self,
         role_mentions: undefined.UndefinedOr[
             typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
         ] = undefined.UNDEFINED,
         /,
-    ) -> _InteractionMessageBuilderT:
+    ) -> Self:
         self._role_mentions = role_mentions
         return self
 
     def set_user_mentions(
-        self: _InteractionMessageBuilderT,
+        self,
         user_mentions: undefined.UndefinedOr[
             typing.Union[snowflakes.SnowflakeishSequence[users.PartialUser], bool]
         ] = undefined.UNDEFINED,
         /,
-    ) -> _InteractionMessageBuilderT:
+    ) -> Self:
         self._user_mentions = user_mentions
         return self
 
@@ -1223,17 +1196,15 @@ def custom_id(self) -> str:
     def components(self) -> typing.Sequence[special_endpoints.ComponentBuilder]:
         return self._components
 
-    def set_title(self: _InteractionModalBuilderT, title: str, /) -> _InteractionModalBuilderT:
+    def set_title(self, title: str, /) -> Self:
         self._title = title
         return self
 
-    def set_custom_id(self: _InteractionModalBuilderT, custom_id: str, /) -> _InteractionModalBuilderT:
+    def set_custom_id(self, custom_id: str, /) -> Self:
         self._custom_id = custom_id
         return self
 
-    def add_component(
-        self: _InteractionModalBuilderT, component: special_endpoints.ComponentBuilder, /
-    ) -> _InteractionModalBuilderT:
+    def add_component(self, component: special_endpoints.ComponentBuilder, /) -> Self:
         self._components.append(component)
         return self
 
@@ -1287,23 +1258,23 @@ def is_nsfw(self) -> undefined.UndefinedOr[bool]:
     def name(self) -> str:
         return self._name
 
-    def set_id(self: _CommandBuilderT, id_: undefined.UndefinedOr[snowflakes.Snowflakeish], /) -> _CommandBuilderT:
+    def set_id(self, id_: undefined.UndefinedOr[snowflakes.Snowflakeish], /) -> Self:
         self._id = snowflakes.Snowflake(id_) if id_ is not undefined.UNDEFINED else undefined.UNDEFINED
         return self
 
     def set_default_member_permissions(
-        self: _CommandBuilderT,
+        self,
         default_member_permissions: typing.Union[undefined.UndefinedType, int, permissions_.Permissions],
         /,
-    ) -> _CommandBuilderT:
+    ) -> Self:
         self._default_member_permissions = default_member_permissions
         return self
 
-    def set_is_dm_enabled(self: _CommandBuilderT, state: undefined.UndefinedOr[bool], /) -> _CommandBuilderT:
+    def set_is_dm_enabled(self, state: undefined.UndefinedOr[bool], /) -> Self:
         self._is_dm_enabled = state
         return self
 
-    def set_is_nsfw(self: _CommandBuilderT, state: undefined.UndefinedOr[bool], /) -> _CommandBuilderT:
+    def set_is_nsfw(self, state: undefined.UndefinedOr[bool], /) -> Self:
         self._is_nsfw = state
         return self
 
@@ -1312,10 +1283,10 @@ def name_localizations(self) -> typing.Mapping[typing.Union[locales.Locale, str]
         return self._name_localizations
 
     def set_name_localizations(
-        self: _CommandBuilderT,
+        self,
         name_localizations: typing.Mapping[typing.Union[locales.Locale, str], str],
         /,
-    ) -> _CommandBuilderT:
+    ) -> Self:
         self._name_localizations = name_localizations
         return self
 
@@ -1355,7 +1326,7 @@ def description(self) -> str:
     def type(self) -> commands.CommandType:
         return commands.CommandType.SLASH
 
-    def add_option(self: _SlashCommandBuilderT, option: commands.CommandOption) -> _SlashCommandBuilderT:
+    def add_option(self, option: commands.CommandOption) -> Self:
         self._options.append(option)
         return self
 
@@ -1370,10 +1341,10 @@ def description_localizations(
         return self._description_localizations
 
     def set_description_localizations(
-        self: _SlashCommandBuilderT,
+        self,
         description_localizations: typing.Mapping[typing.Union[locales.Locale, str], str],
         /,
-    ) -> _SlashCommandBuilderT:
+    ) -> Self:
         self._description_localizations = description_localizations
         return self
 
@@ -1484,6 +1455,10 @@ class _ButtonBuilder(special_endpoints.ButtonBuilder[_ContainerProtoT]):
     _label: undefined.UndefinedOr[str] = attr.field(alias="label", default=undefined.UNDEFINED)
     _is_disabled: bool = attr.field(alias="is_disabled", default=False)
 
+    @property
+    def type(self) -> typing.Literal[component_models.ComponentType.BUTTON]:
+        return component_models.ComponentType.BUTTON
+
     @property
     def style(self) -> typing.Union[int, component_models.ButtonStyle]:
         return self._style
@@ -1501,19 +1476,19 @@ def is_disabled(self) -> bool:
         return self._is_disabled
 
     def set_emoji(
-        self: _ButtonBuilderT,
+        self,
         emoji: typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, undefined.UndefinedType],
         /,
-    ) -> _ButtonBuilderT:
+    ) -> Self:
         self._emoji_id, self._emoji_name = _build_emoji(emoji)
         self._emoji = emoji
         return self
 
-    def set_label(self: _ButtonBuilderT, label: undefined.UndefinedOr[str], /) -> _ButtonBuilderT:
+    def set_label(self, label: undefined.UndefinedOr[str], /) -> Self:
         self._label = label
         return self
 
-    def set_is_disabled(self: _ButtonBuilderT, state: bool, /) -> _ButtonBuilderT:
+    def set_is_disabled(self, state: bool, /) -> Self:
         self._is_disabled = state
         return self
 
@@ -1601,20 +1576,20 @@ def emoji(self) -> typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, unde
     def is_default(self) -> bool:
         return self._is_default
 
-    def set_description(self: _SelectOptionBuilderT, value: undefined.UndefinedOr[str], /) -> _SelectOptionBuilderT:
+    def set_description(self, value: undefined.UndefinedOr[str], /) -> Self:
         self._description = value
         return self
 
     def set_emoji(
-        self: _SelectOptionBuilderT,
+        self,
         emoji: typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, undefined.UndefinedType],
         /,
-    ) -> _SelectOptionBuilderT:
+    ) -> Self:
         self._emoji_id, self._emoji_name = _build_emoji(emoji)
         self._emoji = emoji
         return self
 
-    def set_is_default(self: _SelectOptionBuilderT, state: bool, /) -> _SelectOptionBuilderT:
+    def set_is_default(self, state: bool, /) -> Self:
         self._is_default = state
         return self
 
@@ -1652,6 +1627,10 @@ class SelectMenuBuilder(special_endpoints.SelectMenuBuilder[_ContainerProtoT]):
     _max_values: int = attr.field(alias="max_values", default=1)
     _is_disabled: bool = attr.field(alias="is_disabled", default=False)
 
+    @property
+    def type(self) -> typing.Union[int, component_models.ComponentType]:
+        return self._type
+
     @property
     def custom_id(self) -> str:
         return self._custom_id
@@ -1672,19 +1651,19 @@ def min_values(self) -> int:
     def max_values(self) -> int:
         return self._max_values
 
-    def set_is_disabled(self: _SelectMenuBuilderT, state: bool, /) -> _SelectMenuBuilderT:
+    def set_is_disabled(self, state: bool, /) -> Self:
         self._is_disabled = state
         return self
 
-    def set_placeholder(self: _SelectMenuBuilderT, value: undefined.UndefinedOr[str], /) -> _SelectMenuBuilderT:
+    def set_placeholder(self, value: undefined.UndefinedOr[str], /) -> Self:
         self._placeholder = value
         return self
 
-    def set_min_values(self: _SelectMenuBuilderT, value: int, /) -> _SelectMenuBuilderT:
+    def set_min_values(self, value: int, /) -> Self:
         self._min_values = value
         return self
 
-    def set_max_values(self: _SelectMenuBuilderT, value: int, /) -> _SelectMenuBuilderT:
+    def set_max_values(self, value: int, /) -> Self:
         self._max_values = value
         return self
 
@@ -1711,24 +1690,22 @@ class TextSelectMenuBuilder(
 ):
     """Builder class for text select menus."""
 
-    _type: typing.Union[component_models.ComponentType, int] = component_models.ComponentType.TEXT_SELECT_MENU
+    _type: typing.Literal[component_models.ComponentType.TEXT_SELECT_MENU] = attr.field(
+        default=component_models.ComponentType.TEXT_SELECT_MENU, init=False
+    )
     # Any has to be used here as we can't access Self type in this context
     _options: typing.List[special_endpoints.SelectOptionBuilder[typing.Any]] = attr.field(alias="options", factory=list)
 
     @property
     def options(
-        self: _TextSelectMenuBuilderT,
-    ) -> typing.Sequence[special_endpoints.SelectOptionBuilder[_TextSelectMenuBuilderT]]:
+        self,
+    ) -> typing.Sequence[special_endpoints.SelectOptionBuilder[Self]]:
         return self._options.copy()
 
-    def add_option(
-        self: _TextSelectMenuBuilderT, label: str, value: str, /
-    ) -> special_endpoints.SelectOptionBuilder[_TextSelectMenuBuilderT]:
+    def add_option(self, label: str, value: str, /) -> special_endpoints.SelectOptionBuilder[Self]:
         return _SelectOptionBuilder(menu=self, label=label, value=value)
 
-    def add_raw_option(
-        self: _TextSelectMenuBuilderT, option: special_endpoints.SelectOptionBuilder[_TextSelectMenuBuilderT], /
-    ) -> _TextSelectMenuBuilderT:
+    def add_raw_option(self, option: special_endpoints.SelectOptionBuilder[Self], /) -> Self:
         self._options.append(option)
         return self
 
@@ -1747,15 +1724,15 @@ class ChannelSelectMenuBuilder(
     """Builder class for channel select menus."""
 
     _channel_types: typing.Sequence[channels.ChannelType] = attr.field(alias="channel_types", factory=list)
-    _type: typing.Union[component_models.ComponentType, int] = component_models.ComponentType.CHANNEL_SELECT_MENU
+    _type: typing.Literal[component_models.ComponentType.CHANNEL_SELECT_MENU] = attr.field(
+        default=component_models.ComponentType.CHANNEL_SELECT_MENU, init=False
+    )
 
     @property
     def channel_types(self) -> typing.Sequence[channels.ChannelType]:
         return self._channel_types
 
-    def set_channel_types(
-        self: _ChannelSelectMenuBuilderT, value: typing.Sequence[channels.ChannelType], /
-    ) -> _ChannelSelectMenuBuilderT:
+    def set_channel_types(self, value: typing.Sequence[channels.ChannelType], /) -> Self:
         self._channel_types = value
         return self
 
@@ -1784,6 +1761,10 @@ class TextInputBuilder(special_endpoints.TextInputBuilder[_ContainerProtoT]):
     _min_length: undefined.UndefinedOr[int] = attr.field(alias="min_length", default=undefined.UNDEFINED, kw_only=True)
     _max_length: undefined.UndefinedOr[int] = attr.field(alias="max_length", default=undefined.UNDEFINED, kw_only=True)
 
+    @property
+    def type(self) -> typing.Literal[component_models.ComponentType.TEXT_INPUT]:
+        return component_models.ComponentType.TEXT_INPUT
+
     @property
     def custom_id(self) -> str:
         return self._custom_id
@@ -1816,37 +1797,35 @@ def min_length(self) -> undefined.UndefinedOr[int]:
     def max_length(self) -> undefined.UndefinedOr[int]:
         return self._max_length
 
-    def set_style(
-        self: _TextInputBuilderT, style: typing.Union[component_models.TextInputStyle, int], /
-    ) -> _TextInputBuilderT:
+    def set_style(self, style: typing.Union[component_models.TextInputStyle, int], /) -> Self:
         self._style = component_models.TextInputStyle(style)
         return self
 
-    def set_custom_id(self: _TextInputBuilderT, custom_id: str, /) -> _TextInputBuilderT:
+    def set_custom_id(self, custom_id: str, /) -> Self:
         self._custom_id = custom_id
         return self
 
-    def set_label(self: _TextInputBuilderT, label: str, /) -> _TextInputBuilderT:
+    def set_label(self, label: str, /) -> Self:
         self._label = label
         return self
 
-    def set_placeholder(self: _TextInputBuilderT, placeholder: str, /) -> _TextInputBuilderT:
+    def set_placeholder(self, placeholder: str, /) -> Self:
         self._placeholder = placeholder
         return self
 
-    def set_value(self: _TextInputBuilderT, value: str, /) -> _TextInputBuilderT:
+    def set_value(self, value: str, /) -> Self:
         self._value = value
         return self
 
-    def set_required(self: _TextInputBuilderT, required: bool, /) -> _TextInputBuilderT:
+    def set_required(self, required: bool, /) -> Self:
         self._required = required
         return self
 
-    def set_min_length(self: _TextInputBuilderT, min_length: int, /) -> _TextInputBuilderT:
+    def set_min_length(self, min_length: int, /) -> Self:
         self._min_length = min_length
         return self
 
-    def set_max_length(self: _TextInputBuilderT, max_length: int, /) -> _TextInputBuilderT:
+    def set_max_length(self, max_length: int, /) -> Self:
         self._max_length = max_length
         return self
 
@@ -1877,6 +1856,10 @@ class MessageActionRowBuilder(special_endpoints.MessageActionRowBuilder):
     _components: typing.List[special_endpoints.ComponentBuilder] = attr.field(alias="components", factory=list)
     _stored_type: typing.Optional[component_models.ComponentType] = attr.field(default=None, init=False)
 
+    @property
+    def type(self) -> typing.Literal[component_models.ComponentType.ACTION_ROW]:
+        return component_models.ComponentType.ACTION_ROW
+
     @property
     def components(self) -> typing.Sequence[special_endpoints.ComponentBuilder]:
         return self._components.copy()
@@ -1889,48 +1872,40 @@ def _assert_can_add_type(self, type_: component_models.ComponentType, /) -> None
 
         self._stored_type = type_
 
-    def add_component(
-        self: _MessageActionRowBuilderT, component: special_endpoints.ComponentBuilder, /
-    ) -> _MessageActionRowBuilderT:
+    def add_component(self, component: special_endpoints.ComponentBuilder, /) -> Self:
         self._components.append(component)
         return self
 
     @typing.overload
     def add_button(
-        self: _MessageActionRowBuilderT, style: component_models.InteractiveButtonTypesT, custom_id: str, /
-    ) -> special_endpoints.InteractiveButtonBuilder[_MessageActionRowBuilderT]:
+        self, style: component_models.InteractiveButtonTypesT, custom_id: str, /
+    ) -> special_endpoints.InteractiveButtonBuilder[Self]:
         ...
 
     @typing.overload
     def add_button(
-        self: _MessageActionRowBuilderT,
+        self,
         style: typing.Literal[component_models.ButtonStyle.LINK, 5],
         url: str,
         /,
-    ) -> special_endpoints.LinkButtonBuilder[_MessageActionRowBuilderT]:
+    ) -> special_endpoints.LinkButtonBuilder[Self]:
         ...
 
     @typing.overload
     def add_button(
-        self: _MessageActionRowBuilderT,
+        self,
         style: typing.Union[int, component_models.ButtonStyle],
         url_or_custom_id: str,
         /,
-    ) -> typing.Union[
-        special_endpoints.LinkButtonBuilder[_MessageActionRowBuilderT],
-        special_endpoints.InteractiveButtonBuilder[_MessageActionRowBuilderT],
-    ]:
+    ) -> typing.Union[special_endpoints.LinkButtonBuilder[Self], special_endpoints.InteractiveButtonBuilder[Self],]:
         ...
 
     def add_button(
-        self: _MessageActionRowBuilderT,
+        self,
         style: typing.Union[int, component_models.ButtonStyle],
         url_or_custom_id: str,
         /,
-    ) -> typing.Union[
-        special_endpoints.LinkButtonBuilder[_MessageActionRowBuilderT],
-        special_endpoints.InteractiveButtonBuilder[_MessageActionRowBuilderT],
-    ]:
+    ) -> typing.Union[special_endpoints.LinkButtonBuilder[Self], special_endpoints.InteractiveButtonBuilder[Self],]:
         self._assert_can_add_type(component_models.ComponentType.BUTTON)
         if style in component_models.InteractiveButtonTypes:
             return InteractiveButtonBuilder(container=self, style=style, custom_id=url_or_custom_id)
@@ -1939,47 +1914,47 @@ def add_button(
 
     @typing.overload  # Deprecated overload
     def add_select_menu(
-        self: _MessageActionRowBuilderT,
+        self,
         custom_id: str,
         /,
-    ) -> special_endpoints.TextSelectMenuBuilder[_MessageActionRowBuilderT]:
+    ) -> special_endpoints.TextSelectMenuBuilder[Self]:
         ...
 
     @typing.overload
     def add_select_menu(
-        self: _MessageActionRowBuilderT,
+        self,
         type_: typing.Literal[component_models.ComponentType.TEXT_SELECT_MENU, 3],
         custom_id: str,
         /,
-    ) -> special_endpoints.TextSelectMenuBuilder[_MessageActionRowBuilderT]:
+    ) -> special_endpoints.TextSelectMenuBuilder[Self]:
         ...
 
     @typing.overload
     def add_select_menu(
-        self: _MessageActionRowBuilderT,
+        self,
         type_: typing.Literal[component_models.ComponentType.CHANNEL_SELECT_MENU, 8],
         custom_id: str,
         /,
-    ) -> special_endpoints.ChannelSelectMenuBuilder[_MessageActionRowBuilderT]:
+    ) -> special_endpoints.ChannelSelectMenuBuilder[Self]:
         ...
 
     @typing.overload
     def add_select_menu(
-        self: _MessageActionRowBuilderT,
+        self,
         type_: typing.Union[component_models.ComponentType, int],
         custom_id: str,
         /,
-    ) -> special_endpoints.SelectMenuBuilder[_MessageActionRowBuilderT]:
+    ) -> special_endpoints.SelectMenuBuilder[Self]:
         ...
 
     def add_select_menu(
-        self: _MessageActionRowBuilderT,
+        self,
         type_: typing.Union[component_models.ComponentType, int, str],
         # These have default during the deprecation period for backwards compatibility, as custom_id
         # used to come first
         custom_id: str = "",
         /,
-    ) -> special_endpoints.SelectMenuBuilder[_MessageActionRowBuilderT]:
+    ) -> special_endpoints.SelectMenuBuilder[Self]:
         # custom_id used to come first, so just switch them around if only of them is passed
         if type_ and not custom_id:
             custom_id = str(type_)
@@ -2023,6 +1998,10 @@ class ModalActionRowBuilder(special_endpoints.ModalActionRowBuilder):
         alias="stored_type", init=False, default=None
     )
 
+    @property
+    def type(self) -> typing.Literal[component_models.ComponentType.ACTION_ROW]:
+        return component_models.ComponentType.ACTION_ROW
+
     @property
     def components(self) -> typing.Sequence[special_endpoints.ComponentBuilder]:
         return self._components.copy()
@@ -2035,17 +2014,15 @@ def _assert_can_add_type(self, type_: component_models.ComponentType, /) -> None
 
         self._stored_type = type_
 
-    def add_component(
-        self: _ModalActionRowBuilderT, component: special_endpoints.ComponentBuilder, /
-    ) -> _ModalActionRowBuilderT:
+    def add_component(self, component: special_endpoints.ComponentBuilder, /) -> Self:
         self._components.append(component)
         return self
 
     def add_text_input(
-        self: _ModalActionRowBuilderT,
+        self,
         custom_id: str,
         label: str,
-    ) -> special_endpoints.TextInputBuilder[_ModalActionRowBuilderT]:
+    ) -> special_endpoints.TextInputBuilder[Self]:
         self._assert_can_add_type(component_models.ComponentType.TEXT_INPUT)
         return TextInputBuilder(container=self, custom_id=custom_id, label=label)
 
diff --git a/hikari/interactions/command_interactions.py b/hikari/interactions/command_interactions.py
index fce9bab4..eff6ce0f 100644
--- a/hikari/interactions/command_interactions.py
+++ b/hikari/interactions/command_interactions.py
@@ -46,6 +46,8 @@
 from hikari.internal import attr_extensions
 
 if typing.TYPE_CHECKING:
+    from typing_extensions import Self
+
     from hikari import guilds
     from hikari import permissions as permissions_
     from hikari import users as users_
@@ -101,8 +103,7 @@ class CommandInteractionOption:
     subcommand or group.
     """
 
-    # TODO: use typing.Self here
-    options: typing.Optional[typing.Sequence[CommandInteractionOption]] = attr.field(repr=True)
+    options: typing.Optional[typing.Sequence[Self]] = attr.field(repr=True)
     """Options provided for this option.
 
     Either `CommandInteractionOption.value` or `CommandInteractionOption.options`
@@ -124,18 +125,6 @@ class AutocompleteInteractionOption(CommandInteractionOption):
     even if the option type says otherwise.
     """
 
-    options: typing.Optional[typing.Sequence[AutocompleteInteractionOption]] = attr.field(repr=True)
-    """Options provided for this option.
-
-    Either `AutocompleteInteractionOption.value` or `AutocompleteInteractionOption.options`
-    will be provided with `value` being provided when an option is provided as a
-    parameter with a value and `options` being provided when an option donates a
-    subcommand or group.
-
-    `AutocompleteInteractionOption.is_focused` will be `True` for the value being
-    autocompleted.
-    """
-
 
 @attr_extensions.with_copy
 @attr.define(hash=True, kw_only=True, weakref_slot=False)
diff --git a/hikari/internal/cache.py b/hikari/internal/cache.py
index af307d49..ed9efeb2 100644
--- a/hikari/internal/cache.py
+++ b/hikari/internal/cache.py
@@ -67,6 +67,8 @@
 from hikari.internal import collections
 
 if typing.TYPE_CHECKING:
+    from typing_extensions import Self
+
     from hikari import applications
     from hikari import channels as channels_
     from hikari import components as components_
@@ -320,7 +322,7 @@ def build_entity(self, app: traits.RESTAware, /) -> ValueT:
 
     @classmethod
     @abc.abstractmethod
-    def build_from_entity(cls: typing.Type[DataT], entity: ValueT, /) -> DataT:
+    def build_from_entity(cls, entity: ValueT, /) -> Self:
         """Build a data object from an initialised entity.
 
         Parameters
diff --git a/hikari/internal/collections.py b/hikari/internal/collections.py
index 0245af81..83df4ee9 100644
--- a/hikari/internal/collections.py
+++ b/hikari/internal/collections.py
@@ -24,7 +24,6 @@
 from __future__ import annotations
 
 __all__: typing.Sequence[str] = (
-    "ExtendedMapT",
     "KeyT",
     "ValueT",
     "SnowflakeSet",
@@ -43,7 +42,9 @@
 
 from hikari import snowflakes
 
-ExtendedMapT = typing.TypeVar("ExtendedMapT", bound="ExtendedMutableMapping[typing.Any, typing.Any]")
+if typing.TYPE_CHECKING:
+    from typing_extensions import Self
+
 """Type-hint A type hint used for mapped collection objects."""
 KeyT = typing.TypeVar("KeyT", bound=typing.Hashable)
 """Type-hint A type hint used for the type of a mapping's key."""
@@ -64,7 +65,7 @@ class ExtendedMutableMapping(typing.MutableMapping[KeyT, ValueT], abc.ABC):
     __slots__: typing.Sequence[str] = ()
 
     @abc.abstractmethod
-    def copy(self: ExtendedMapT) -> ExtendedMapT:
+    def copy(self) -> Self:
         """Return a copy of this mapped collection.
 
         Unlike simply doing `dict(mapping)`, this may rely on internal detail
diff --git a/hikari/internal/enums.py b/hikari/internal/enums.py
index fc1def29..9798a6fb 100644
--- a/hikari/internal/enums.py
+++ b/hikari/internal/enums.py
@@ -31,6 +31,9 @@
 import types
 import typing
 
+if typing.TYPE_CHECKING:
+    from typing_extensions import Self
+
 _T = typing.TypeVar("_T")
 _MAX_CACHED_MEMBERS: typing.Final[int] = 1 << 12
 
@@ -161,11 +164,11 @@ def __iter__(cls) -> typing.Iterator[typing.Any]:
         yield from cls._name_to_member_map_.values()
 
     def __new__(
-        mcs: typing.Type[_T],
+        mcs,
         name: str,
         bases: typing.Tuple[typing.Type[typing.Any], ...],
         namespace: typing.Union[typing.Dict[str, typing.Any], _EnumNamespace],
-    ) -> _T:
+    ) -> Self:
         global _Enum
 
         if _Enum is NotImplemented:
@@ -426,11 +429,11 @@ def __prepare__(
 
     @staticmethod
     def __new__(
-        mcs: typing.Type[_T],
+        mcs,
         name: str,
         bases: typing.Tuple[typing.Type[typing.Any], ...],
         namespace: typing.Union[typing.Dict[str, typing.Any], _EnumNamespace],
-    ) -> _T:
+    ) -> Self:
         global _Flag
 
         if _Flag is NotImplemented:
@@ -669,7 +672,7 @@ def value(self) -> int:
         """Return the `int` value of the flag."""
         return self._value_
 
-    def all(self: _T, *flags: _T) -> bool:
+    def all(self, *flags: Self) -> bool:
         """Check if all of the given flags are part of this value.
 
         Returns
@@ -680,7 +683,7 @@ def all(self: _T, *flags: _T) -> bool:
         """
         return all((flag & self) == flag for flag in flags)
 
-    def any(self: _T, *flags: _T) -> bool:
+    def any(self, *flags: Self) -> bool:
         """Check if any of the given flags are part of this value.
 
         Returns
@@ -691,7 +694,7 @@ def any(self: _T, *flags: _T) -> bool:
         """
         return any((flag & self) == flag for flag in flags)
 
-    def difference(self: _T, other: typing.Union[_T, int]) -> _T:
+    def difference(self, other: typing.Union[Self, int]) -> _T:
         """Perform a set difference with the other set.
 
         This will return all flags in this set that are not in the other value.
@@ -700,18 +703,18 @@ def difference(self: _T, other: typing.Union[_T, int]) -> _T:
         """
         return self.__class__(self & ~int(other))
 
-    def intersection(self: _T, other: typing.Union[_T, int]) -> _T:
+    def intersection(self, other: typing.Union[Self, int]) -> _T:
         """Return a combination of flags that are set for both given values.
 
         Equivalent to using the "AND" `&` operator.
         """
         return self.__class__(self._value_ & int(other))
 
-    def invert(self: _T) -> _T:
+    def invert(self) -> Self:
         """Return a set of all flags not in the current set."""
         return self.__class__(self.__class__.__everything__._value_ & ~self._value_)
 
-    def is_disjoint(self: _T, other: typing.Union[_T, int]) -> bool:
+    def is_disjoint(self, other: typing.Union[Self, int]) -> bool:
         """Return whether two sets have a intersection or not.
 
         If the two sets have an intersection, then this returns
@@ -720,18 +723,18 @@ def is_disjoint(self: _T, other: typing.Union[_T, int]) -> bool:
         """
         return not (self & other)
 
-    def is_subset(self: _T, other: typing.Union[_T, int]) -> bool:
+    def is_subset(self, other: typing.Union[Self, int]) -> bool:
         """Return whether another set contains this set or not.
 
         Equivalent to using the "in" operator.
         """
         return (self & other) == other
 
-    def is_superset(self: _T, other: typing.Union[_T, int]) -> bool:
+    def is_superset(self, other: typing.Union[Self, int]) -> bool:
         """Return whether this set contains another set or not."""
         return (self & other) == self
 
-    def none(self: _T, *flags: _T) -> bool:
+    def none(self, *flags: Self) -> bool:
         """Check if none of the given flags are part of this value.
 
         .. note::
@@ -745,7 +748,7 @@ def none(self: _T, *flags: _T) -> bool:
         """
         return not self.any(*flags)
 
-    def split(self: _T) -> typing.Sequence[_T]:
+    def split(self) -> typing.Sequence[Self]:
         """Return a list of all defined atomic values for this flag.
 
         Any unrecognised bits will be omitted for brevity.
@@ -758,7 +761,7 @@ def split(self: _T) -> typing.Sequence[_T]:
             key=lambda m: m._name_,
         )
 
-    def symmetric_difference(self: _T, other: typing.Union[_T, int]) -> _T:
+    def symmetric_difference(self, other: typing.Union[_T, int]) -> Self:
         """Return a set with the symmetric differences of two flag sets.
 
         Equivalent to using the "XOR" `^` operator.
@@ -767,7 +770,7 @@ def symmetric_difference(self: _T, other: typing.Union[_T, int]) -> _T:
         """
         return self.__class__(self._value_ ^ int(other))
 
-    def union(self: _T, other: typing.Union[_T, int]) -> _T:
+    def union(self, other: typing.Union[_T, int]) -> Self:
         """Return a combination of all flags in this set and the other set.
 
         Equivalent to using the "OR" `~` operator.
@@ -791,7 +794,7 @@ def __bool__(self) -> bool:
     def __int__(self) -> int:
         return self._value_
 
-    def __iter__(self: _T) -> typing.Iterator[_T]:
+    def __iter__(self) -> typing.Iterator[Self]:
         return iter(self.split())
 
     def __len__(self) -> int:
@@ -800,7 +803,7 @@ def __len__(self) -> int:
     def __repr__(self) -> str:
         return f"<{self.__class__.__name__}.{self.name}: {self.value!r}>"
 
-    def __rsub__(self: _T, other: typing.Union[int, _T]) -> _T:
+    def __rsub__(self, other: typing.Union[int, _T]) -> Self:
         # This logic has to be reversed to be correct, since order matters for
         # a subtraction operator. This also ensures `int - _T -> _T` is a valid
         # case for us.
diff --git a/hikari/internal/enums.pyi b/hikari/internal/enums.pyi
index 9832676b..79af942f 100644
--- a/hikari/internal/enums.pyi
+++ b/hikari/internal/enums.pyi
@@ -40,32 +40,32 @@ from typing import Sequence as __Sequence
 from typing import TypeVar as __TypeVar
 from typing import Union as __Union
 
-Enum = __enum.Enum
+from typing_extensions import Self as __Self
 
-__FlagT = __TypeVar("__FlagT", bound=__enum.IntFlag)
+Enum = __enum.Enum
 
 class Flag(__enum.IntFlag):
-    def all(self: __FlagT, *flags: __FlagT) -> bool: ...
-    def any(self: __FlagT, *flags: __FlagT) -> bool: ...
-    def difference(self: __FlagT, other: __Union[int, __FlagT]) -> __FlagT: ...
-    def intersection(self: __FlagT, other: __Union[int, __FlagT]) -> __FlagT: ...
-    def invert(self: __FlagT) -> __FlagT: ...
-    def is_disjoint(self: __FlagT, other: __Union[int, __FlagT]) -> bool: ...
-    def is_subset(self: __FlagT, other: __Union[int, __FlagT]) -> bool: ...
-    def is_superset(self: __FlagT, other: __Union[int, __FlagT]) -> bool: ...
-    def none(self, *flags: __FlagT) -> bool: ...
-    def split(self: __FlagT) -> __Sequence[__FlagT]: ...
-    def symmetric_difference(self: __FlagT, other: __Union[int, __FlagT]) -> __FlagT: ...
-    def union(self: __FlagT, other: __Union[int, __FlagT]) -> __FlagT: ...
-    def __iter__(self: __FlagT) -> __Iterator[__FlagT]: ...
+    def all(self, *flags: __Self) -> bool: ...
+    def any(self, *flags: __Self) -> bool: ...
+    def difference(self, other: __Union[int, __Self]) -> __Self: ...
+    def intersection(self, other: __Union[int, __Self]) -> __Self: ...
+    def invert(self) -> __Self: ...
+    def is_disjoint(self, other: __Union[int, __Self]) -> bool: ...
+    def is_subset(self, other: __Union[int, __Self]) -> bool: ...
+    def is_superset(self, other: __Union[int, __Self]) -> bool: ...
+    def none(self, *flags: __Self) -> bool: ...
+    def split(self) -> __Sequence[__Self]: ...
+    def symmetric_difference(self, other: __Union[int, __Self]) -> __Self: ...
+    def union(self, other: __Union[int, __Self]) -> __Self: ...
+    def __iter__(self) -> __Iterator[__Self]: ...
     def __len__(self) -> int: ...
     # Aliases
-    def isdisjoint(self: __FlagT, other: __Union[int, __FlagT]) -> bool: ...  # is_disjoint
-    def issuperset(self: __FlagT, other: __Union[int, __FlagT]) -> bool: ...  # is_superset
-    def symmetricdifference(self: __FlagT, other: __Union[int, __FlagT]) -> __FlagT: ...  # symmetric_difference
-    def issubset(self: __FlagT, other: __Union[int, __FlagT]) -> bool: ...  # is_subset
+    def isdisjoint(self, other: __Union[int, __Self]) -> bool: ...  # is_disjoint
+    def issuperset(self, other: __Union[int, __Self]) -> bool: ...  # is_superset
+    def symmetricdifference(self, other: __Union[int, __Self]) -> __Self: ...  # symmetric_difference
+    def issubset(self, other: __Union[int, __Self]) -> bool: ...  # is_subset
     # '__invert__' is explicitly defined as a special case because it is typed as returning 'int' in typeshed
-    def __invert__(self: __FlagT) -> __FlagT: ...  # invert
+    def __invert__(self) -> __Self: ...  # invert
 
 _V = __TypeVar("_V")
 
diff --git a/hikari/internal/fast_protocol.py b/hikari/internal/fast_protocol.py
index 289267ee..ac6d01e1 100644
--- a/hikari/internal/fast_protocol.py
+++ b/hikari/internal/fast_protocol.py
@@ -29,7 +29,7 @@
 import typing
 
 if typing.TYPE_CHECKING:
-    _T = typing.TypeVar("_T")
+    from typing_extensions import Self
 
 _Protocol: FastProtocolChecking = NotImplemented
 _IGNORED_ATTRS = typing.EXCLUDED_ATTRIBUTES + ["__qualname__", "__slots__"]
@@ -45,11 +45,11 @@ class _FastProtocolChecking(type(typing.Protocol)):
     _attributes_: typing.Tuple[str, ...]
 
     def __new__(
-        cls: typing.Type[_T],
+        cls,
         cls_name: str,
         bases: typing.Tuple[typing.Type[typing.Any], ...],
         namespace: typing.Dict[str, typing.Any],
-    ) -> _T:
+    ) -> Self:
         global _Protocol
 
         if _Protocol is NotImplemented:
@@ -90,7 +90,7 @@ def __new__(
 
         return cls
 
-    def __instancecheck__(self: _T, other: typing.Any) -> bool:
+    def __instancecheck__(self, other: typing.Any) -> bool:
         if not self._is_protocol:
             return super().__instancecheck__(other)
 
diff --git a/hikari/stickers.py b/hikari/stickers.py
index db767ccd..e41dd6b9 100644
--- a/hikari/stickers.py
+++ b/hikari/stickers.py
@@ -79,6 +79,12 @@ class StickerFormatType(int, enums.Enum):
     """A GIF sticker."""
 
 
+_STICKER_EXTENSIONS: typing.Dict[typing.Union[StickerFormatType, int], str] = {
+    StickerFormatType.LOTTIE: "json",
+    StickerFormatType.GIF: "gif",
+}
+
+
 @attr.define(hash=True, kw_only=True, weakref_slot=False)
 class StickerPack(snowflakes.Unique):
     """Represents a sticker pack on Discord."""
@@ -156,9 +162,9 @@ def image_url(self) -> files.URL:
         """URL for the image.
 
         The extension will be based on `format_type`. If `format_type` is `StickerFormatType.LOTTIE`,
-        then the extension will be `.json`. Otherwise, it will be `.png`.
+        then the extension will be `.json`, if it's `StickerFormatType.GIF` it will be `.gif`. Otherwise, it will be `.png`.
         """
-        ext = "json" if self.format_type is StickerFormatType.LOTTIE else "png"
+        ext = _STICKER_EXTENSIONS.get(self.format_type, "png")
 
         return routes.CDN_STICKER.compile_to_file(urls.CDN_URL, sticker_id=self.id, file_format=ext)
 
diff --git a/hikari/traits.py b/hikari/traits.py
index 118fddeb..fb2b2ac4 100644
--- a/hikari/traits.py
+++ b/hikari/traits.py
@@ -40,6 +40,7 @@
     "VoiceAware",
 )
 
+import abc
 import typing
 
 from hikari import presences
@@ -50,6 +51,8 @@
     import datetime
     from concurrent import futures
 
+    from typing_extensions import Self
+
     from hikari import channels
     from hikari import guilds
     from hikari import intents as intents_
@@ -65,8 +68,6 @@
     from hikari.api import shard as gateway_shard
     from hikari.api import voice as voice_
 
-    _RESTBotAwareT = typing.TypeVar("_RESTBotAwareT", bound="RESTBotAware")
-
 
 @typing.runtime_checkable
 class NetworkSettingsAware(fast_protocol.FastProtocolChecking, typing.Protocol):
@@ -75,11 +76,13 @@ class NetworkSettingsAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def http_settings(self) -> config.HTTPSettings:
         """HTTP settings in use by this component."""
         raise NotImplementedError
 
     @property
+    @abc.abstractmethod
     def proxy_settings(self) -> config.ProxySettings:
         """Proxy settings in use by this component."""
         raise NotImplementedError
@@ -95,6 +98,7 @@ class EventManagerAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def event_manager(self) -> event_manager_.EventManager:
         """Event manager for this object."""
         raise NotImplementedError
@@ -110,6 +114,7 @@ class EntityFactoryAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def entity_factory(self) -> entity_factory_.EntityFactory:
         """Entity factory implementation for this object."""
         raise NotImplementedError
@@ -127,6 +132,7 @@ class ExecutorAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def executor(self) -> typing.Optional[futures.Executor]:
         """Executor to use for blocking operations.
 
@@ -146,6 +152,7 @@ class EventFactoryAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def event_factory(self) -> event_factory_.EventFactory:
         """Event factory component."""
         raise NotImplementedError
@@ -158,6 +165,7 @@ class IntentsAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def intents(self) -> intents_.Intents:
         """Intents registered for the application."""
         raise NotImplementedError
@@ -175,6 +183,7 @@ class RESTAware(
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def rest(self) -> rest_.RESTClient:
         """REST client to use for HTTP requests."""
         raise NotImplementedError
@@ -191,6 +200,7 @@ class VoiceAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def voice(self) -> voice_.VoiceComponent:
         """Voice connection manager component for this application."""
         raise NotImplementedError
@@ -214,6 +224,7 @@ class ShardAware(
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def heartbeat_latencies(self) -> typing.Mapping[int, float]:
         """Mapping of shard ID to heartbeat latency.
 
@@ -222,6 +233,7 @@ def heartbeat_latencies(self) -> typing.Mapping[int, float]:
         raise NotImplementedError
 
     @property
+    @abc.abstractmethod
     def heartbeat_latency(self) -> float:
         """Average heartbeat latency of all started shards.
 
@@ -230,6 +242,7 @@ def heartbeat_latency(self) -> float:
         raise NotImplementedError
 
     @property
+    @abc.abstractmethod
     def shards(self) -> typing.Mapping[int, gateway_shard.GatewayShard]:
         """Mapping of shards in this application instance.
 
@@ -241,6 +254,7 @@ def shards(self) -> typing.Mapping[int, gateway_shard.GatewayShard]:
         raise NotImplementedError
 
     @property
+    @abc.abstractmethod
     def shard_count(self) -> int:
         """Number of shards in the total application.
 
@@ -249,6 +263,7 @@ def shard_count(self) -> int:
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     def get_me(self) -> typing.Optional[users_.OwnUser]:
         """Return the bot user, if known.
 
@@ -264,6 +279,7 @@ def get_me(self) -> typing.Optional[users_.OwnUser]:
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     async def update_presence(
         self,
         *,
@@ -308,6 +324,7 @@ async def update_presence(
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     async def update_voice_state(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
@@ -340,6 +357,7 @@ async def update_voice_state(
             client.
         """
 
+    @abc.abstractmethod
     async def request_guild_members(
         self,
         guild: snowflakes.SnowflakeishOr[guilds.PartialGuild],
@@ -395,6 +413,7 @@ class InteractionServerAware(RESTAware, EntityFactoryAware, fast_protocol.FastPr
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def interaction_server(self) -> interaction_server_.InteractionServer:
         """Interaction server this app is bound to."""
         raise NotImplementedError
@@ -410,6 +429,7 @@ class CacheAware(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def cache(self) -> cache_.Cache:
         """Immutable cache implementation for this object."""
         raise NotImplementedError
@@ -422,6 +442,7 @@ class Runnable(fast_protocol.FastProtocolChecking, typing.Protocol):
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def is_alive(self) -> bool:
         """Whether the application is running or not.
 
@@ -431,9 +452,11 @@ def is_alive(self) -> bool:
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     async def close(self) -> None:
         """Kill the application by shutting all components down."""
 
+    @abc.abstractmethod
     async def join(self) -> None:
         """Wait indefinitely until the application closes.
 
@@ -443,10 +466,12 @@ async def join(self) -> None:
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     def run(self) -> None:
         """Start the application and block until it's finished running."""
         raise NotImplementedError
 
+    @abc.abstractmethod
     async def start(self) -> None:
         """Start the application and then return."""
         raise NotImplementedError
@@ -475,19 +500,22 @@ class RESTBotAware(InteractionServerAware, Runnable, fast_protocol.FastProtocolC
     __slots__: typing.Sequence[str] = ()
 
     @property
+    @abc.abstractmethod
     def on_shutdown(
-        self: _RESTBotAwareT,
-    ) -> typing.Sequence[typing.Callable[[_RESTBotAwareT], typing.Coroutine[typing.Any, typing.Any, None]]]:
+        self,
+    ) -> typing.Sequence[typing.Callable[[Self], typing.Coroutine[typing.Any, typing.Any, None]]]:
         """Sequence of the bot's asynchronous shutdown callbacks."""
         raise NotImplementedError
 
     @property
+    @abc.abstractmethod
     def on_startup(
-        self: _RESTBotAwareT,
-    ) -> typing.Sequence[typing.Callable[[_RESTBotAwareT], typing.Coroutine[typing.Any, typing.Any, None]]]:
+        self,
+    ) -> typing.Sequence[typing.Callable[[Self], typing.Coroutine[typing.Any, typing.Any, None]]]:
         """Sequence of the bot's asynchronous startup callbacks."""
         raise NotImplementedError
 
+    @abc.abstractmethod
     def add_shutdown_callback(
         self, callback: typing.Callable[[RESTBotAware], typing.Coroutine[typing.Any, typing.Any, None]], /
     ) -> None:
@@ -500,6 +528,7 @@ def add_shutdown_callback(
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     def remove_shutdown_callback(
         self, callback: typing.Callable[[RESTBotAware], typing.Coroutine[typing.Any, typing.Any, None]], /
     ) -> None:
@@ -517,6 +546,7 @@ def remove_shutdown_callback(
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     def add_startup_callback(
         self, callback: typing.Callable[[RESTBotAware], typing.Coroutine[typing.Any, typing.Any, None]], /
     ) -> None:
@@ -529,6 +559,7 @@ def add_startup_callback(
         """
         raise NotImplementedError
 
+    @abc.abstractmethod
     def remove_startup_callback(
         self, callback: typing.Callable[[RESTBotAware], typing.Coroutine[typing.Any, typing.Any, None]], /
     ) -> None:
diff --git a/hikari/undefined.py b/hikari/undefined.py
index 1d53496f..9bd4a289 100644
--- a/hikari/undefined.py
+++ b/hikari/undefined.py
@@ -36,7 +36,8 @@
 
 import typing
 
-SelfT = typing.TypeVar("SelfT")
+if typing.TYPE_CHECKING:
+    from typing_extensions import Self
 
 
 class UndefinedType:
@@ -47,11 +48,11 @@ class UndefinedType:
     def __bool__(self) -> typing.Literal[False]:
         return False
 
-    def __copy__(self: SelfT) -> SelfT:
+    def __copy__(self) -> Self:
         # This is meant to be a singleton
         return self
 
-    def __deepcopy__(self: SelfT, memo: typing.MutableMapping[int, typing.Any]) -> SelfT:
+    def __deepcopy__(self, memo: typing.MutableMapping[int, typing.Any]) -> Self:
         memo[id(self)] = self
 
         # This is meant to be a singleton


Test patch:
diff --git a/tests/hikari/impl/test_buckets.py b/tests/hikari/impl/test_buckets.py
index 5ee3a0bf..fb802c8e 100644
--- a/tests/hikari/impl/test_buckets.py
+++ b/tests/hikari/impl/test_buckets.py
@@ -151,7 +151,7 @@ class TestRESTBucketManager:
     @pytest.fixture()
     def bucket_manager(self):
         manager = buckets.RESTBucketManager(max_rate_limit=float("inf"))
-        manager._closed_event = mock.Mock(wait=mock.AsyncMock(), is_set=mock.Mock(return_value=False))
+        manager._gc_task = object()
 
         return manager
 
@@ -161,32 +161,43 @@ def test_max_rate_limit_property(self, bucket_manager):
         assert bucket_manager.max_rate_limit is bucket_manager._max_rate_limit
 
     @pytest.mark.asyncio()
-    async def test_close_closes_all_buckets(self, bucket_manager):
+    async def test_close(self, bucket_manager):
+        class GcTaskMock:
+            def __init__(self):
+                self._awaited_count = 0
+                self.cancel = mock.Mock()
+
+            def __await__(self):
+                if False:
+                    yield  # Turns it into a generator
+
+                self._awaited_count += 1
+
+            def __call__(self):
+                return self
+
+            def assert_awaited_once(self):
+                assert self._awaited_count == 1
+
         buckets_array = [mock.Mock() for _ in range(30)]
         bucket_manager._real_hashes_to_buckets = {f"blah{i}": b for i, b in enumerate(buckets_array)}
+        bucket_manager._gc_task = gc_task = GcTaskMock()
 
-        bucket_manager.close()
+        await bucket_manager.close()
 
         assert bucket_manager._real_hashes_to_buckets == {}
 
         for i, b in enumerate(buckets_array):
             b.close.assert_called_once(), i
 
-    @pytest.mark.asyncio()
-    async def test_close_sets_closed_event(self, bucket_manager):
-        closed_event = mock.Mock()
-        bucket_manager._closed_event = closed_event
-
-        bucket_manager.close()
-
-        assert bucket_manager._closed_event is None
-        closed_event.set.assert_called_once()
+        assert bucket_manager._gc_task is None
+        gc_task.cancel.assert_called_once_with()
+        gc_task.assert_awaited_once()
 
     @pytest.mark.asyncio()
     async def test_start(self, bucket_manager):
-        bucket_manager._closed_event = None
+        bucket_manager._gc_task = None
 
-        assert bucket_manager._gc_task is None
         bucket_manager.start()
         assert bucket_manager._gc_task is not None
 
@@ -199,41 +210,18 @@ async def test_start(self, bucket_manager):
 
     @pytest.mark.asyncio()
     async def test_start_when_already_started(self, bucket_manager):
-        bucket_manager._closed_event = object()
+        bucket_manager._gc_task = object()
 
         with pytest.raises(errors.ComponentStateConflictError):
             bucket_manager.start()
 
-    @pytest.mark.asyncio()
-    async def test_gc_polls_until_closed_event_set(self, event_loop, bucket_manager):
-        bucket_manager._closed_event = asyncio.Event()
-
-        # Start the gc and initial assertions
-        task = event_loop.create_task(bucket_manager._gc(0.001, float("inf")))
-        assert not task.done()
-
-        # [First poll] event not set => shouldn't complete the task
-        await asyncio.sleep(0.001)
-        assert not task.done()
-
-        # [Second poll] event not set during poll => shouldn't complete the task
-        await asyncio.sleep(0.001)
-        bucket_manager._closed_event.set()
-        assert not task.done()
-
-        # [Third poll] event set => should complete the task
-        await asyncio.sleep(0.001)
-        assert task.done()
-
     @pytest.mark.asyncio()
     async def test_gc_makes_gc_pass(self, bucket_manager):
         class ExitError(Exception):
             ...
 
-        bucket_manager._closed_event.wait = mock.Mock()
-
         with mock.patch.object(buckets.RESTBucketManager, "_purge_stale_buckets") as purge_stale_buckets:
-            with mock.patch.object(asyncio, "wait_for", side_effect=[asyncio.TimeoutError, ExitError]):
+            with mock.patch.object(asyncio, "sleep", side_effect=[None, ExitError]):
                 with pytest.raises(ExitError):
                     await bucket_manager._gc(0.001, 33)
 
@@ -431,7 +419,7 @@ async def test_update_rate_limits_updates_params(self, bucket_manager):
                 bucket_manager.update_rate_limits(route, "auth", "123", 22, 23, 5.32)
                 bucket.update_rate_limit.assert_called_once_with(22, 23, 27 + 5.32)
 
-    @pytest.mark.parametrize(("closed_event", "is_alive"), [(None, False), ("some", True)])
-    def test_is_alive(self, bucket_manager, closed_event, is_alive):
-        bucket_manager._closed_event = closed_event
+    @pytest.mark.parametrize(("gc_task", "is_alive"), [(None, False), ("some", True)])
+    def test_is_alive(self, bucket_manager, gc_task, is_alive):
+        bucket_manager._gc_task = gc_task
         assert bucket_manager.is_alive is is_alive
diff --git a/tests/hikari/impl/test_event_manager_base.py b/tests/hikari/impl/test_event_manager_base.py
index b4f6859e..74492195 100644
--- a/tests/hikari/impl/test_event_manager_base.py
+++ b/tests/hikari/impl/test_event_manager_base.py
@@ -24,10 +24,8 @@
 import asyncio
 import contextlib
 import gc
-import logging
 import sys
 import typing
-import unittest
 import warnings
 import weakref
 
@@ -214,13 +212,11 @@ def test___del___for_active_stream(self):
         streamer._event_type = base_events.Event
         streamer._active = True
 
-        with unittest.TestCase().assertLogs("hikari.event_manager", level=logging.WARNING) as logging_watcher:
+        with mock.patch.object(event_manager_base, "_LOGGER") as logger:
             del streamer
             gc.collect()  # Force a GC collection
 
-        assert logging_watcher.output == [
-            "WARNING:hikari.event_manager:active 'Event' streamer fell out of scope before being closed"
-        ]
+        logger.warning.assert_called_once_with("active %r streamer fell out of scope before being closed", "Event")
         close_method.assert_called_once_with()
 
     def test___del___for_inactive_stream(self):
diff --git a/tests/hikari/impl/test_rest.py b/tests/hikari/impl/test_rest.py
index 732164f1..1a062e5d 100644
--- a/tests/hikari/impl/test_rest.py
+++ b/tests/hikari/impl/test_rest.py
@@ -679,6 +679,7 @@ def test_token_type_property(self, rest_client):
     async def test_close(self, rest_client, client_session_owner, bucket_manager_owner):
         rest_client._close_event = mock_close_event = mock.Mock()
         rest_client._client_session.close = client_close = mock.AsyncMock()
+        rest_client._bucket_manager.close = bucket_close = mock.AsyncMock()
         rest_client._client_session_owner = client_session_owner
         rest_client._bucket_manager_owner = bucket_manager_owner
 
@@ -695,7 +696,7 @@ async def test_close(self, rest_client, client_session_owner, bucket_manager_own
             assert rest_client._client_session is not None
 
         if bucket_manager_owner:
-            rest_client._bucket_manager.close.assert_called_once_with()
+            bucket_close.assert_awaited_once_with()
         else:
             rest_client._bucket_manager.assert_not_called()
 
diff --git a/tests/hikari/impl/test_rest_bot.py b/tests/hikari/impl/test_rest_bot.py
index 2d846aaf..79d10e99 100644
--- a/tests/hikari/impl/test_rest_bot.py
+++ b/tests/hikari/impl/test_rest_bot.py
@@ -213,7 +213,7 @@ def test___init___generates_default_settings(self):
         stack.enter_context(mock.patch.object(interaction_server_impl, "InteractionServer"))
 
         with stack:
-            result = cls("token", "token_type")
+            result = cls("token")
 
             rest_impl.RESTClientImpl.assert_called_once_with(
                 cache=None,
@@ -225,7 +225,7 @@ def test___init___generates_default_settings(self):
                 proxy_settings=config.ProxySettings.return_value,
                 rest_url=None,
                 token="token",
-                token_type="token_type",
+                token_type="Bot",
             )
 
             config.HTTPSettings.assert_called_once()
diff --git a/tests/hikari/impl/test_special_endpoints.py b/tests/hikari/impl/test_special_endpoints.py
index a5edf56b..80e8f732 100644
--- a/tests/hikari/impl/test_special_endpoints.py
+++ b/tests/hikari/impl/test_special_endpoints.py
@@ -20,6 +20,8 @@
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
 
+import typing
+
 import mock
 import pytest
 
@@ -1212,6 +1214,9 @@ def button(self):
             is_disabled=True,
         )
 
+    def test_type_property(self, button):
+        assert button.type is components.ComponentType.BUTTON
+
     def test_style_property(self, button):
         assert button.style is components.ButtonStyle.DANGER
 
@@ -1441,6 +1446,11 @@ class TestSelectMenuBuilder:
     def menu(self):
         return special_endpoints.SelectMenuBuilder(container=mock.Mock(), custom_id="o2o2o2", type=5)
 
+    def test_type_property(self):
+        menu = special_endpoints.SelectMenuBuilder(container=mock.Mock(), type=123, custom_id="hihihi")
+
+        assert menu.type == 123
+
     def test_custom_id_property(self, menu):
         assert menu.custom_id == "o2o2o2"
 
@@ -1481,6 +1491,9 @@ class TestTextSelectMenuBuilder:
     def menu(self):
         return special_endpoints.TextSelectMenuBuilder(container=mock.Mock(), custom_id="o2o2o2")
 
+    def test_type_property(self, menu: special_endpoints.TextSelectMenuBuilder[typing.Any]):
+        assert menu.type is components.ComponentType.TEXT_SELECT_MENU
+
     def test_add_add_option(self, menu):
         option = menu.add_option("ok", "no u")
         option.add_to_menu()
@@ -1513,6 +1526,17 @@ def test_build(self):
 
 
 class TestChannelSelectMenuBuilder:
+    def test_type_property(self):
+        menu = special_endpoints.ChannelSelectMenuBuilder(container=mock.Mock(), custom_id="id")
+        assert menu.type is components.ComponentType.CHANNEL_SELECT_MENU
+
+    def test_set_channel_types(self):
+        menu = special_endpoints.ChannelSelectMenuBuilder(container=mock.Mock(), custom_id="hi")
+
+        menu.set_channel_types([channels.ChannelType.DM, channels.ChannelType.GUILD_FORUM])
+
+        assert menu.channel_types == [channels.ChannelType.DM, channels.ChannelType.GUILD_FORUM]
+
     def test_build(self):
         result = (
             special_endpoints.ChannelSelectMenuBuilder(container=object(), custom_id="o2o2o2")
@@ -1544,6 +1568,9 @@ def text_input(self):
             label="label",
         )
 
+    def test_type_property(self, text_input):
+        assert text_input.type is components.ComponentType.TEXT_INPUT
+
     def test_set_style(self, text_input):
         assert text_input.set_style(components.TextInputStyle.PARAGRAPH) is text_input
         assert text_input.style == components.TextInputStyle.PARAGRAPH
@@ -1623,6 +1650,11 @@ def test_build_partial(self):
 
 
 class TestMessageActionRowBuilder:
+    def test_type_property(self):
+        row = special_endpoints.MessageActionRowBuilder()
+
+        assert row.type is components.ComponentType.ACTION_ROW
+
     def test_components_property(self):
         mock_component = object()
         row = special_endpoints.MessageActionRowBuilder().add_component(mock_component)
@@ -1670,6 +1702,11 @@ def test_build(self):
 
 
 class TestModalActionRow:
+    def test_type_property(self):
+        row = special_endpoints.ModalActionRowBuilder()
+
+        assert row.type is components.ComponentType.ACTION_ROW
+
     def test_add_text_input(self):
         row = special_endpoints.ModalActionRowBuilder()
         menu = row.add_text_input("hihihi", "label")