diff --git a/package.json b/package.json
index 41b9a2544da82105715eaab8814cd84404991196..2e298ff3fcfa9c664948d9fce65a63aee4f166b5 100644
--- a/package.json
+++ b/package.json
@@ -94,7 +94,7 @@
     "react-router-dom": "^5.2.0",
     "react-scroll": "^1.8.2",
     "redux": "^4.1.0",
-    "revolt.js": "4.3.3-alpha.7",
+    "revolt.js": "4.3.3-alpha.8",
     "rimraf": "^3.0.2",
     "sass": "^1.35.1",
     "shade-blend-color": "^1.0.0",
diff --git a/src/components/common/AutoComplete.tsx b/src/components/common/AutoComplete.tsx
index 0e0f399da111e2276555137281e8d6bfa00000cb..565f4a4ac2fd34f8ba0694aaaf61c088f457c47e 100644
--- a/src/components/common/AutoComplete.tsx
+++ b/src/components/common/AutoComplete.tsx
@@ -384,7 +384,7 @@ export default function AutoComplete({ detached, state, setState, onClick }: Pic
                                 })
                             }
                             onClick={onClick}>
-                            <Emoji emoji={(emojiDictionary as any)[match]} size={20} />
+                            <Emoji emoji={(emojiDictionary as Record<string, string>)[match]} size={20} />
                             :{match}:
                         </button>
                     ))}
diff --git a/src/components/common/LocaleSelector.tsx b/src/components/common/LocaleSelector.tsx
index fbebe8f114d4242090090a0b2dc0891f0fb1d3c2..7f91b1c7a3063eec5f63dd373c797dee3819af81 100644
--- a/src/components/common/LocaleSelector.tsx
+++ b/src/components/common/LocaleSelector.tsx
@@ -1,7 +1,7 @@
 import ComboBox from "../ui/ComboBox";
 import { dispatch } from "../../redux";
 import { connectState } from "../../redux/connector";
-import { LanguageEntry, Languages } from "../../context/Locale";
+import { Language, LanguageEntry, Languages } from "../../context/Locale";
 
 type Props = {
     locale: string;
@@ -14,12 +14,12 @@ export function LocaleSelector(props: Props) {
             onChange={e =>
                 dispatch({
                     type: "SET_LOCALE",
-                    locale: e.currentTarget.value as any
+                    locale: e.currentTarget.value as Language
                 })
             }
         >
             {Object.keys(Languages).map(x => {
-                const l = (Languages as any)[x] as LanguageEntry;
+                const l = Languages[x as keyof typeof Languages];
                 return (
                     <option value={x}>
                         {l.emoji} {l.display}
diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx
index 46edea72c2c8db2f72856e7c296102cffc605a71..f00aad634dec4f7e7b7151039dd636dca0c4b4c2 100644
--- a/src/components/common/messaging/Message.tsx
+++ b/src/components/common/messaging/Message.tsx
@@ -35,7 +35,12 @@ function Message({ attachContext, message, contrast, content: replacement, head:
     const content = message.content as string;
     const head = preferHead || (message.replies && message.replies.length > 0);
 
-    const userContext = attachContext ? attachContextMenu('Menu', { user: message.author, contextualChannel: message.channel }) : undefined as any; // ! FIXME: tell fatal to make this type generic
+     // ! FIXME: tell fatal to make this type generic
+    // bree: Fatal please...
+    const userContext = attachContext 
+        ? attachContextMenu('Menu', { user: message.author, contextualChannel: message.channel }) as any
+        : undefined;
+
     const openProfile = () => openScreen({ id: 'profile', user_id: message.author });
 
     return (
diff --git a/src/components/common/messaging/attachments/AttachmentActions.tsx b/src/components/common/messaging/attachments/AttachmentActions.tsx
index 2009229b6ab18f4d9cf74c5eeff618467c2b6f43..8b297f4becb000814764698ea314b911d53e7186 100644
--- a/src/components/common/messaging/attachments/AttachmentActions.tsx
+++ b/src/components/common/messaging/attachments/AttachmentActions.tsx
@@ -19,7 +19,8 @@ export default function AttachmentActions({ attachment }: Props) {
     const open_url = `${url}/${filename}`;
     const download_url = url.replace('attachments', 'attachments/download')
 
-    const filesize = determineFileSize(size as any);
+    // for some reason revolt.js says the size is a string even though it's a number
+    const filesize = determineFileSize(size);
 
     switch (metadata.type) {
         case 'Image':
diff --git a/src/components/markdown/Renderer.tsx b/src/components/markdown/Renderer.tsx
index 115cad68d749154929f55e41c854611ab7fcae52..61575a8650f59c71ce6897bd9e8a9ac2d7a34f83 100644
--- a/src/components/markdown/Renderer.tsx
+++ b/src/components/markdown/Renderer.tsx
@@ -22,13 +22,21 @@ import MarkdownSup from "markdown-it-sup";
 // @ts-ignore
 import MarkdownSub from "markdown-it-sub";
 
+// TODO: global.d.ts file for defining globals
+declare global {
+    interface Window {
+        copycode: (element: HTMLDivElement) => void
+    }
+}
+
+
 // Handler for code block copy.
 if (typeof window !== "undefined") {
-    (window as any).copycode = function(element: HTMLDivElement) {
+    window.copycode = function(element: HTMLDivElement) {
         try {
             let code = element.parentElement?.parentElement?.children[1];
             if (code) {
-                navigator.clipboard.writeText((code as any).innerText.trim());
+                navigator.clipboard.writeText(code.textContent?.trim() ?? '');
             }
         } catch (e) {}
     };
@@ -65,10 +73,17 @@ const defaultRender =
         return self.renderToken(tokens, idx, options);
     };
 
+// TODO: global.d.ts file for defining globals
+declare global {
+    interface Window {
+        internalHandleURL: (element: HTMLAnchorElement) => void
+    }
+}
+
 // Handler for internal links, pushes events to React using magic.
 if (typeof window !== "undefined") {
-    (window as any).internalHandleURL = function(element: HTMLAnchorElement) {
-        const url = new URL(element.href, location as any);
+    window.internalHandleURL = function(element: HTMLAnchorElement) {
+        const url = new URL(element.href, location.href);
         const pathname = url.pathname;
 
         if (pathname.startsWith("/@")) {
@@ -87,7 +102,7 @@ md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
             // For internal links, we should use our own handler to use react-router history.
             // @ts-ignore
             const href = tokens[idx].attrs[hIndex][1];
-            const url = new URL(href, location as any);
+            const url = new URL(href, location.href);
 
             if (url.hostname === location.hostname) {
                 internal = true;
@@ -161,7 +176,7 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) {
             data-large-emojis={useLargeEmojis}
             onClick={ev => {
                 if (ev.target) {
-                    let element: Element = ev.target as any;
+                    let element = ev.currentTarget;
                     if (element.classList.contains("spoiler")) {
                         element.classList.add("shown");
                     }
diff --git a/src/components/navigation/right/MemberSidebar.tsx b/src/components/navigation/right/MemberSidebar.tsx
index 303b86c00d3644b202b3f7f8ba222e70dfd0890f..40be8041dd0fcae9d11a6313c9a0a680bdadff88 100644
--- a/src/components/navigation/right/MemberSidebar.tsx
+++ b/src/components/navigation/right/MemberSidebar.tsx
@@ -56,12 +56,8 @@ export function GroupMemberSidebar({ channel, ctx }: Props & { channel: Channels
 
     members.sort((a, b) => {
         // ! FIXME: should probably rewrite all this code
-        let l = ((a.online &&
-            a.status?.presence !== Users.Presence.Invisible) ??
-            false) as any | 0;
-        let r = ((b.online &&
-            b.status?.presence !== Users.Presence.Invisible) ??
-            false) as any | 0;
+        let l = +((a.online && a.status?.presence !== Users.Presence.Invisible) ?? false) | 0;
+        let r = +((b.online && b.status?.presence !== Users.Presence.Invisible) ?? false) | 0;
 
         let n = r - l;
         if (n !== 0) {
@@ -161,12 +157,8 @@ export function ServerMemberSidebar({ channel, ctx }: Props & { channel: Channel
     // copy paste from above
     users.sort((a, b) => {
         // ! FIXME: should probably rewrite all this code
-        let l = ((a.online &&
-            a.status?.presence !== Users.Presence.Invisible) ??
-            false) as any | 0;
-        let r = ((b.online &&
-            b.status?.presence !== Users.Presence.Invisible) ??
-            false) as any | 0;
+        let l = +((a.online && a.status?.presence !== Users.Presence.Invisible) ?? false) | 0;
+        let r = +((b.online && b.status?.presence !== Users.Presence.Invisible) ?? false) | 0;
 
         let n = r - l;
         if (n !== 0) {
diff --git a/src/context/Locale.tsx b/src/context/Locale.tsx
index 873d57a67fff81de7aa71512c5f825868813ecb3..6fdff9e216a3173b2e8e6eedac9b9744d9d70d6e 100644
--- a/src/context/Locale.tsx
+++ b/src/context/Locale.tsx
@@ -114,9 +114,11 @@ interface Props {
 }
 
 function Locale({ children, locale }: Props) {
-    const [defns, setDefinition] = useState(definition);
+    // TODO: create and use LanguageDefinition type here
+    const [defns, setDefinition] = useState<Record<string, unknown>>(definition);
     const lang = Languages[locale];
 
+    // TODO: clean this up and use the built in Intl API
     function transformLanguage(source: { [key: string]: any }) {
         const obj = defaultsDeep(source, definition);
 
diff --git a/src/context/Settings.tsx b/src/context/Settings.tsx
index 7f834feaeeb723d63bccf2373655ffdc74d4c011..3653b93e772ada8c62710b82ada757949047e955 100644
--- a/src/context/Settings.tsx
+++ b/src/context/Settings.tsx
@@ -15,8 +15,8 @@ import { Children } from "../types/Preact";
 import { createContext } from "preact";
 import { useMemo } from "preact/hooks";
 
-export const SettingsContext = createContext<Settings>({} as any);
-export const SoundContext = createContext<(sound: Sounds) => void>({} as any);
+export const SettingsContext = createContext<Settings>({});
+export const SoundContext = createContext<((sound: Sounds) => void)>(null!);
 
 interface Props {
     children?: Children,
diff --git a/src/context/Theme.tsx b/src/context/Theme.tsx
index 51f425545daf0e49e4c8ca743bbc59ba80ce4386..8a9fc54e11c32954e398f3ab4826726eb64376ef 100644
--- a/src/context/Theme.tsx
+++ b/src/context/Theme.tsx
@@ -30,7 +30,15 @@ export type Variables =
     | "status-away"
     | "status-busy"
     | "status-streaming"
-    | "status-invisible";
+    | "status-invisible"
+
+// While this isn't used, it'd be good to keep this up to date as a reference or for future use
+export type HiddenVariables =
+    | "font"
+    | "ligatures"
+    | "app-height"
+    | "sidebar-active"
+    | "monospace-font"
 
 export type Fonts = 'Open Sans' | 'Inter' | 'Atkinson Hyperlegible' | 'Roboto' | 'Noto Sans' | 'Lato' | 'Bree Serif' | 'Montserrat' | 'Poppins' | 'Raleway' | 'Ubuntu' | 'Comic Neue';
 export type MonoscapeFonts = 'Fira Code' | 'Roboto Mono' | 'Source Code Pro' | 'Space Mono' | 'Ubuntu Mono';
@@ -191,7 +199,7 @@ export const DEFAULT_FONT = 'Open Sans';
 export const DEFAULT_MONO_FONT = 'Fira Code';
 
 // Generated from https://gitlab.insrt.uk/revolt/community/themes
-export const PRESETS: { [key: string]: Theme } = {
+export const PRESETS: Record<string, Theme> = {
     light: {
         light: true,
         accent: "#FD6671",
@@ -217,7 +225,7 @@ export const PRESETS: { [key: string]: Theme } = {
         "status-away": "#F39F00",
         "status-busy": "#F84848",
         "status-streaming": "#977EFF",
-        "status-invisible": "#A5A5A5",
+        "status-invisible": "#A5A5A5"
     },
     dark: {
         light: false,
@@ -244,7 +252,7 @@ export const PRESETS: { [key: string]: Theme } = {
         "status-away": "#F39F00",
         "status-busy": "#F84848",
         "status-streaming": "#977EFF",
-        "status-invisible": "#A5A5A5",
+        "status-invisible": "#A5A5A5"
     },
 };
 
@@ -259,7 +267,8 @@ const GlobalTheme = createGlobalStyle<{ theme: Theme }>`
 }
 `;
 
-export const ThemeContext = createContext<Theme>({} as any);
+// Load the default default them and apply extras later
+export const ThemeContext = createContext<Theme>(PRESETS['dark']);
 
 interface Props {
     children: Children;
@@ -269,7 +278,7 @@ interface Props {
 function Theme({ children, options }: Props) {
     const theme: Theme = {
         ...PRESETS["dark"],
-        ...(PRESETS as any)[options?.preset as any],
+        ...PRESETS[options?.preset ?? ''],
         ...options?.custom
     };
 
diff --git a/src/context/Voice.tsx b/src/context/Voice.tsx
index ac5c40777bf1b5a92b01b643128a03d93b8da519..6190c363d31c14909d7032f418fe27ba23b8e05b 100644
--- a/src/context/Voice.tsx
+++ b/src/context/Voice.tsx
@@ -33,8 +33,9 @@ export interface VoiceState {
     participants?: Readonly<Map<string, VoiceUser>>;
 }
 
-export const VoiceContext = createContext<VoiceState>(undefined as any);
-export const VoiceOperationsContext = createContext<VoiceOperations>(undefined as any);
+// They should be present from first render. - insert's words
+export const VoiceContext = createContext<VoiceState>(null!);
+export const VoiceOperationsContext = createContext<VoiceOperations>(null!);
 
 type Props = {
     children: Children;
diff --git a/src/context/intermediate/modals/Onboarding.tsx b/src/context/intermediate/modals/Onboarding.tsx
index 8f3894d8c2132af5e3eb96c81cc9ab12212046cf..3f328191a9f8bbb804cecdef303f6569c9b428b5 100644
--- a/src/context/intermediate/modals/Onboarding.tsx
+++ b/src/context/intermediate/modals/Onboarding.tsx
@@ -1,6 +1,6 @@
 import { Text } from "preact-i18n";
 import { useState } from "preact/hooks";
-import { useForm } from "react-hook-form";
+import { SubmitHandler, useForm } from "react-hook-form";
 import styles from "./Onboarding.module.scss";
 import { takeError } from "../../revoltjs/util";
 import Button from "../../../components/ui/Button";
@@ -14,12 +14,16 @@ interface Props {
     callback: (username: string, loginAfterSuccess?: true) => Promise<void>;
 }
 
+interface FormInputs {
+    username: string
+}
+
 export function OnboardingModal({ onClose, callback }: Props) {
-    const { handleSubmit, register } = useForm();
+    const { handleSubmit, register } = useForm<FormInputs>();
     const [loading, setLoading] = useState(false);
     const [error, setError] = useState<string | undefined>(undefined);
 
-    async function onSubmit({ username }: { username: string }) {
+    const onSubmit: SubmitHandler<FormInputs> = ({ username }) => {
         setLoading(true);
         callback(username, true)
             .then(onClose)
@@ -45,7 +49,7 @@ export function OnboardingModal({ onClose, callback }: Props) {
                         <p>
                             <Text id="app.special.modals.onboarding.pick" />
                         </p>
-                        <form onSubmit={handleSubmit(onSubmit) as any}>
+                        <form onSubmit={handleSubmit(onSubmit) as JSX.GenericEventHandler<HTMLFormElement>}>
                             <div>
                                 <FormField
                                     type="username"
diff --git a/src/context/intermediate/popovers/ModifyAccount.tsx b/src/context/intermediate/popovers/ModifyAccount.tsx
index 2deb2b8cef6d7a3578310d2856ac416218309941..25477c0768b99a61149b2c12d8103afca363fb9f 100644
--- a/src/context/intermediate/popovers/ModifyAccount.tsx
+++ b/src/context/intermediate/popovers/ModifyAccount.tsx
@@ -1,5 +1,5 @@
 import { Text } from "preact-i18n";
-import { useForm } from "react-hook-form";
+import { SubmitHandler, useForm } from "react-hook-form";
 import Modal from "../../../components/ui/Modal";
 import { takeError } from "../../revoltjs/util";
 import { useContext, useState } from "preact/hooks";
@@ -12,22 +12,28 @@ interface Props {
     field: "username" | "email" | "password";
 }
 
+interface FormInputs {
+    password: string,
+    new_email: string,
+    new_username: string,
+    new_password: string,
+
+    // TODO: figure out if this is correct or not
+    // it wasn't in the types before this was typed but the element itself was there
+    current_password?: string
+}
+
 export function ModifyAccountModal({ onClose, field }: Props) {
     const client = useContext(AppContext);
-    const { handleSubmit, register, errors } = useForm();
+    const { handleSubmit, register, errors } = useForm<FormInputs>();
     const [error, setError] = useState<string | undefined>(undefined);
 
-    async function onSubmit({
+    const onSubmit: SubmitHandler<FormInputs> = async ({
         password,
         new_username,
         new_email,
         new_password
-    }: {
-        password: string;
-        new_username: string;
-        new_email: string;
-        new_password: string;
-    }) {
+    }) => {
         try {
             if (field === "email") {
                 await client.req("POST", "/auth/change/email", {
@@ -75,7 +81,8 @@ export function ModifyAccountModal({ onClose, field }: Props) {
                 }
             ]}
         >
-            <form onSubmit={handleSubmit(onSubmit) as any}>
+            {/* Preact / React typing incompatabilities */}
+            <form onSubmit={handleSubmit(onSubmit) as JSX.GenericEventHandler<HTMLFormElement>}>
                 {field === "email" && (
                     <FormField
                         type="email"
diff --git a/src/context/revoltjs/FileUploads.tsx b/src/context/revoltjs/FileUploads.tsx
index 74fa2753c45f95bd8a3cb082b474f40831c50ae2..87781e2f2ef9cb78b2c59dc995010a693446db34 100644
--- a/src/context/revoltjs/FileUploads.tsx
+++ b/src/context/revoltjs/FileUploads.tsx
@@ -44,8 +44,8 @@ export function grabFiles(maxFileSize: number, cb: (files: File[]) => void, tooL
     input.type = "file";
     input.multiple = multiple ?? false;
 
-    input.onchange = async e => {
-        const files = (e.target as any)?.files;
+    input.onchange = async (e) => {
+        const files = (e.currentTarget as HTMLInputElement)?.files;
         if (!files) return;
         for (let file of files) {
             if (file.size > maxFileSize) {
diff --git a/src/context/revoltjs/Notifications.tsx b/src/context/revoltjs/Notifications.tsx
index dc90617beb3d85594158cb5468bfdd88ad74fcee..4ae6c74a61da7fd3fcf025d3c8aa0ff020847673 100644
--- a/src/context/revoltjs/Notifications.tsx
+++ b/src/context/revoltjs/Notifications.tsx
@@ -216,7 +216,7 @@ function Notifier({ options, notifs }: Props) {
             document.removeEventListener("visibilitychange", visChange);
     }, [guild_id, channel_id]);
 
-    return <></>;
+    return null;
 }
 
 const NotifierComponent = connectState(
diff --git a/src/context/revoltjs/RevoltClient.tsx b/src/context/revoltjs/RevoltClient.tsx
index ea33dfb15d0c5333906ec200918f01cb73bd0be6..91dc602f0bdc2724b4b55fdf271b6a4fe4edc0d4 100644
--- a/src/context/revoltjs/RevoltClient.tsx
+++ b/src/context/revoltjs/RevoltClient.tsx
@@ -34,9 +34,12 @@ export interface ClientOperations {
     openDM: (user_id: string) => Promise<string>;
 }
 
-export const AppContext = createContext<Client>(undefined as any);
-export const StatusContext = createContext<ClientStatus>(undefined as any);
-export const OperationsContext = createContext<ClientOperations>(undefined as any);
+// By the time they are used, they should all be initialized.
+// Currently the app does not render until a client is built and the other two are always initialized on first render.
+// - insert's words
+export const AppContext = createContext<Client>(null!);
+export const StatusContext = createContext<ClientStatus>(null!);
+export const OperationsContext = createContext<ClientOperations>(null!);
 
 type Props = {
     auth: AuthState;
@@ -93,16 +96,14 @@ function Context({ auth, children }: Props) {
                     const login = () =>
                         dispatch({
                             type: "LOGIN",
-                            session: client.session as any
+                            session: client.session! // This [null assertion] is ok, we should have a session by now. - insert's words
                         });
 
                     if (onboarding) {
                         openScreen({
                             id: "onboarding",
-                            callback: async (username: string) => {
-                                await (onboarding as any)(username, true);
-                                login();
-                            }
+                            callback: (username: string) =>
+                                onboarding(username, true).then(login)
                         });
                     } else {
                         login();
diff --git a/src/context/revoltjs/StateMonitor.tsx b/src/context/revoltjs/StateMonitor.tsx
index bffdfdbb09225a0376b2894220ae2cfec971d353..cc0d7616196af52da5a2233eb48ddb8400c96164 100644
--- a/src/context/revoltjs/StateMonitor.tsx
+++ b/src/context/revoltjs/StateMonitor.tsx
@@ -63,7 +63,7 @@ function StateMonitor(props: Props) {
         return () => clearInterval(interval);
     }, [ props.typing ]);
 
-    return <></>;
+    return null;
 }
 
 export default connectState(
diff --git a/src/context/revoltjs/SyncManager.tsx b/src/context/revoltjs/SyncManager.tsx
index 285713f3ceb5dacafae4e20f8fcdfa4c9d187390..f09ffb0d1ca7477e4c715085267f541b85f680e5 100644
--- a/src/context/revoltjs/SyncManager.tsx
+++ b/src/context/revoltjs/SyncManager.tsx
@@ -23,11 +23,11 @@ type Props = {
 
 var lastValues: { [key in SyncKeys]?: any } = { };
 
-export function mapSync(packet: Sync.UserSettings, revision?: { [key: string]: number }) {
+export function mapSync(packet: Sync.UserSettings, revision?: Record<string, number>) {
     let update: { [key in SyncKeys]?: [ number, SyncData[key] ] } = {};
     for (let key of Object.keys(packet)) {
         let [ timestamp, obj ] = packet[key];
-        if (timestamp < (revision ?? {} as any)[key] ?? 0) {
+        if (timestamp < (revision ?? {})[key] ?? 0) {
             continue;
         }
 
@@ -110,7 +110,7 @@ function SyncManager(props: Props) {
         return () => client.removeListener('packet', onPacket);
     }, [ disabled, props.sync ]);
 
-    return <></>;
+    return null;
 }
 
 export default connectState(
diff --git a/src/context/revoltjs/events.ts b/src/context/revoltjs/events.ts
index 089415124144407a18d1025f17c5d3229e37bed5..319894689955981271fff384005383b3855eee60 100644
--- a/src/context/revoltjs/events.ts
+++ b/src/context/revoltjs/events.ts
@@ -31,7 +31,7 @@ export function registerEvents({
         }
     }
 
-    const listeners = {
+    let listeners: Record<string, (...args: any[]) => void> = {
         connecting: () =>
             operations.ready() && setStatus(ClientStatus.CONNECTING),
 
@@ -86,21 +86,18 @@ export function registerEvents({
         ready: () => setStatus(ClientStatus.ONLINE)
     };
 
-    let listenerFunc: { [key: string]: Function };
     if (import.meta.env.DEV) {
-        listenerFunc = {};
-        for (const listener of Object.keys(listeners)) {
-            listenerFunc[listener] = (...args: any[]) => {
-                console.debug(`Calling ${listener} with`, args);
-                (listeners as any)[listener](...args);
-            };
-        }
-    } else {
-        listenerFunc = listeners;
+        listeners = new Proxy(listeners, {
+            get: (target, listener, receiver) => (...args: unknown[]) => {
+                console.debug(`Calling ${listener.toString()} with`, args);
+                Reflect.get(target, listener)(...args)
+            }
+        })
     }
 
-    for (const listener of Object.keys(listenerFunc)) {
-        client.addListener(listener, (listenerFunc as any)[listener]);
+    // TODO: clean this a bit and properly handle types
+    for (const listener in listeners) {
+        client.addListener(listener, listeners[listener]);
     }
 
     function logMutation(target: string, key: string) {
@@ -134,8 +131,8 @@ export function registerEvents({
     window.addEventListener("offline", offline);
 
     return () => {
-        for (const listener of Object.keys(listenerFunc)) {
-            client.removeListener(listener, (listenerFunc as any)[listener]);
+        for (const listener in listeners) {
+            client.removeListener(listener, listeners[listener as keyof typeof listeners]);
         }
 
         if (import.meta.env.DEV) {
diff --git a/src/context/revoltjs/hooks.ts b/src/context/revoltjs/hooks.ts
index f57038bbd12bfc7bd6d12736ea79bef67c93a9fc..fac889862a8075df4e1e85707062b9e09d06a172 100644
--- a/src/context/revoltjs/hooks.ts
+++ b/src/context/revoltjs/hooks.ts
@@ -2,6 +2,7 @@ import { useCallback, useContext, useEffect, useState } from "preact/hooks";
 import { Channels, Servers, Users } from "revolt.js/dist/api/objects";
 import { Client, PermissionCalculator } from 'revolt.js';
 import { AppContext } from "./RevoltClient";
+import Collection from "revolt.js/dist/maps/Collection";
 
 export interface HookContext {
     client: Client,
@@ -25,7 +26,16 @@ export function useForceUpdate(context?: HookContext): HookContext {
     return { client, forceUpdate: () => updateState(Math.random()) };
 }
 
-function useObject(type: string, id?: string | string[], context?: HookContext) {
+// TODO: utils.d.ts maybe?
+type PickProperties<T, U> = Pick<T, {
+    [K in keyof T]: T[K] extends U ? K : never
+}[keyof T]>
+
+// The keys in Client that are an object
+// for some reason undefined keeps appearing despite there being no reason to so it's filtered out
+type ClientCollectionKey = Exclude<keyof PickProperties<Client, Collection<any>>, undefined>;
+
+function useObject(type: ClientCollectionKey, id?: string | string[], context?: HookContext) {
     const ctx = useForceUpdate(context);
 
     function update(target: any) {
@@ -35,7 +45,7 @@ function useObject(type: string, id?: string | string[], context?: HookContext)
         }
     }
 
-    const map = (ctx.client as any)[type];
+    const map = ctx.client[type];
     useEffect(() => {
         map.addListener("update", update);
         return () => map.removeListener("update", update);
diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx
index 5c5769f9ce43efea5c025a5bf62d78906555983d..89f1a6bb87f906c6cde55a35b4ab5b7590a13251 100644
--- a/src/lib/ContextMenus.tsx
+++ b/src/lib/ContextMenus.tsx
@@ -307,11 +307,15 @@ function ContextMenus(props: Props) {
                 case "delete_server":
                 case "delete_message":
                 case "create_channel":
-                // @ts-expect-error
-                case "create_invite": openScreen({ id: "special_prompt", type: data.action, target: data.target }); break;
+                case "create_invite":
+                    // The any here is because typescript flattens the case types into a single type and type structure and specifity is lost or whatever
+                    openScreen({ id: "special_prompt", type: data.action, target: data.target as any }); 
+                    break;
 
                 case "ban_member":
-                case "kick_member": openScreen({ id: "special_prompt", type: data.action, target: data.target, user: data.user }); break;
+                case "kick_member": 
+                    openScreen({ id: "special_prompt", type: data.action, target: data.target, user: data.user });
+                    break;
 
                 case "open_notification_options": {
                     openContextMenu("NotificationOptions", { channel: data.channel });
@@ -427,7 +431,7 @@ function ContextMenus(props: Props) {
                     }
 
                     if (user) {
-                        let actions: string[];
+                        let actions: Action['action'][];
                         switch (user.relationship) {
                             case Users.Relationship.User: actions = []; break;
                             case Users.Relationship.Friend:
@@ -461,11 +465,9 @@ function ContextMenus(props: Props) {
                             generateAction({ action: 'message_user', user: user._id });
                         }
 
-                        for (const action of actions) {
-                            generateAction({
-                                action: action as any,
-                                user
-                            });
+                        for(let i = 0; i < actions.length; i++) {
+                            // The any here is because typescript can't determine that user the actions are linked together correctly
+                            generateAction({ action: actions[i] as any, user })
                         }
                     }
 
diff --git a/src/pages/login/FormField.tsx b/src/pages/login/FormField.tsx
index eb7f498899a4e8598ec0c842fe26fa7ebfa2d7a7..94a36098d7bda22f459b56d4d2bf3da804f1067b 100644
--- a/src/pages/login/FormField.tsx
+++ b/src/pages/login/FormField.tsx
@@ -26,6 +26,8 @@ export default function FormField({
             )}
             <Localizer>
                 <InputBox
+                    // Styled uses React typing while we use Preact
+                    // this leads to inconsistances where things need to be typed oddly
                     placeholder={(<Text id={`login.enter.${type}`} />) as any}
                     name={
                         type === "current_password" ? "password" : name ?? type
diff --git a/src/pages/login/forms/Form.tsx b/src/pages/login/forms/Form.tsx
index d1e0e8c4bf29cad75255770210feece26f2f49e1..66791ec3529280d13ae99278b1e1b0331b1f00c7 100644
--- a/src/pages/login/forms/Form.tsx
+++ b/src/pages/login/forms/Form.tsx
@@ -35,6 +35,12 @@ function getInviteCode() {
     return code ?? '';
 }
 
+interface FormInputs {
+    email: string
+    password: string
+    invite: string
+}
+
 export function Form({ page, callback }: Props) {
     const client = useContext(AppContext);
 
@@ -43,7 +49,7 @@ export function Form({ page, callback }: Props) {
     const [error, setGlobalError] = useState<string | undefined>(undefined);
     const [captcha, setCaptcha] = useState<CaptchaProps | undefined>(undefined);
 
-    const { handleSubmit, register, errors, setError } = useForm({
+    const { handleSubmit, register, errors, setError } = useForm<FormInputs>({
         defaultValues: {
             email: '',
             password: '',
@@ -51,11 +57,7 @@ export function Form({ page, callback }: Props) {
         }
     });
 
-    async function onSubmit(data: {
-        email: string;
-        password: string;
-        invite: string;
-    }) {
+    async function onSubmit(data: FormInputs) {
         setGlobalError(undefined);
         setLoading(true);
 
@@ -143,7 +145,8 @@ export function Form({ page, callback }: Props) {
     return (
         <div className={styles.form}>
             <img src={wideSVG} />
-            <form onSubmit={handleSubmit(onSubmit) as any}>
+            {/* Preact / React typing incompatabilities */}
+            <form onSubmit={handleSubmit(onSubmit) as JSX.GenericEventHandler<HTMLFormElement>}>
                 {page !== "reset" && (
                     <FormField
                         type="email"
diff --git a/src/pages/login/forms/FormReset.tsx b/src/pages/login/forms/FormReset.tsx
index a8a7886b903e35cd55fefe7c859dee4400e6dd72..ac73d0186563e03c1e62b9dd4208877a9c8cca17 100644
--- a/src/pages/login/forms/FormReset.tsx
+++ b/src/pages/login/forms/FormReset.tsx
@@ -25,9 +25,9 @@ export function FormReset() {
         <Form
             page="reset"
             callback={async data => {
-                await client.req("POST", "/auth/reset" as any, {
+                await client.req("POST", "/auth/reset", {
                     token,
-                    ...(data as any)
+                    ...data
                 });
                 history.push("/login");
             }}
diff --git a/src/pages/settings/panes/Account.tsx b/src/pages/settings/panes/Account.tsx
index 7a849e0e45e01b704ba38064b384fbe7fc0c6bbb..88a7839c70b7e53a71451de484fb3a5624ed129d 100644
--- a/src/pages/settings/panes/Account.tsx
+++ b/src/pages/settings/panes/Account.tsx
@@ -52,11 +52,11 @@ export function Account() {
                 <div className={styles.username}>@{user.username}</div>
             </div>
             <div className={styles.details}>
-                {[
+                {([
                     ["username", user.username, <At size={24} />],
                     ["email", email, <Envelope size={24} />],
                     ["password", "*****", <Key size={24} />]
-                ].map(([field, value, icon]) => (
+                ] as const).map(([field, value, icon]) => (
                     <div>
                         {icon}
                         <div className={styles.detail}>
@@ -70,7 +70,7 @@ export function Account() {
                                 onClick={() =>
                                     openScreen({
                                         id: "modify_account",
-                                        field: field as any
+                                        field: field
                                     })
                                 }
                                 contrast
diff --git a/src/pages/settings/panes/Appearance.tsx b/src/pages/settings/panes/Appearance.tsx
index 58426b3199ac555deedb19ba74ed74aa782a5723..714e4086ec8a7bb04743dd6d2245236d5ee2886a 100644
--- a/src/pages/settings/panes/Appearance.tsx
+++ b/src/pages/settings/panes/Appearance.tsx
@@ -226,7 +226,7 @@ export function Component(props: Props) {
                     </Button>
                 </div>
                 <div className={styles.overrides}>
-                    {[
+                    {([
                         "accent",
                         "background",
                         "foreground",
@@ -240,7 +240,6 @@ export function Component(props: Props) {
                         "block",
                         "message-box",
                         "mention",
-                        "sidebar-active",
                         "scrollbar-thumb",
                         "scrollbar-track",
                         "status-online",
@@ -252,15 +251,15 @@ export function Component(props: Props) {
                         "warning",
                         "error",
                         "hover"
-                    ].map(x => (
+                    ] as const).map(x => (
                         <div className={styles.entry} key={x}>
                             <span>{x}</span>
                             <div className={styles.override}>
                                 <div className={styles.picker}
-                                    style={{ backgroundColor: (theme as any)[x as any] }}>
+                                    style={{ backgroundColor: theme[x] }}>
                                     <input
                                         type="color"
-                                        value={(theme as any)[x as any]}
+                                        value={theme[x]}
                                         onChange={v =>
                                             setOverride({
                                                 [x]: v.currentTarget.value
@@ -270,7 +269,7 @@ export function Component(props: Props) {
                                 </div>
                                 <InputBox
                                     className={styles.text}
-                                    value={(theme as any)[x as any]}
+                                    value={theme[x]}
                                     onChange={y =>
                                         setOverride({
                                             [x]: y.currentTarget.value
diff --git a/src/pages/settings/panes/Notifications.tsx b/src/pages/settings/panes/Notifications.tsx
index ae3c165780a67aa852eef7d0cce66f52dbef9a6d..5098c85e9266c9291ea5b9c981e0ce9757c32aee 100644
--- a/src/pages/settings/panes/Notifications.tsx
+++ b/src/pages/settings/panes/Notifications.tsx
@@ -77,11 +77,11 @@ export function Component({ options }: Props) {
 
                                 // tell the server we just subscribed
                                 const json = sub.toJSON();
-                                if (json.keys) {
+                                if (json.keys) {;
                                     client.req("POST", "/push/subscribe", {
                                         endpoint: sub.endpoint,
-                                        ...json.keys
-                                    } as any);
+                                        ...(json.keys as { p256dh: string, auth: string })
+                                    });
                                     setPushEnabled(true);
                                 }
                             } else {
diff --git a/src/pages/settings/panes/Profile.tsx b/src/pages/settings/panes/Profile.tsx
index 941d311d1b3a880de03bddfb8a3895b00b18226e..1b6fa429e0a61b1a9c0679033aad07dd6a367e13 100644
--- a/src/pages/settings/panes/Profile.tsx
+++ b/src/pages/settings/panes/Profile.tsx
@@ -11,7 +11,7 @@ import { ClientStatus, StatusContext } from "../../../context/revoltjs/RevoltCli
 import AutoComplete, { useAutoComplete } from "../../../components/common/AutoComplete";
 
 export function Profile() {
-    const { intl } = useContext(IntlContext) as any;
+    const { intl } = useContext(IntlContext);
     const status = useContext(StatusContext);
 
     const ctx = useForceUpdate();
@@ -121,7 +121,7 @@ export function Profile() {
                             : "placeholder"
                     }`,
                     "",
-                    intl.dictionary
+                    (intl as any).dictionary as Record<string, unknown>
                 )}
                 onKeyUp={onKeyUp}
                 onKeyDown={onKeyDown}
diff --git a/src/pages/settings/panes/Sessions.tsx b/src/pages/settings/panes/Sessions.tsx
index b9bccc4b9767a7a89ed960a081466d595392fb28..2ec357be7e352aea5d0ad1676eaa554f2b29e7d6 100644
--- a/src/pages/settings/panes/Sessions.tsx
+++ b/src/pages/settings/panes/Sessions.tsx
@@ -155,7 +155,7 @@ export function Sessions() {
                                     ]);
                                     await client.req(
                                         "DELETE",
-                                        `/auth/sessions/${session.id}` as any
+                                        `/auth/sessions/${session.id}` as '/auth/sessions'
                                     );
                                     setSessions(
                                         sessions?.filter(
diff --git a/yarn.lock b/yarn.lock
index 9362c74f3ae5c17a53db45780b63bd428793f403..6fec18642ef22fc373748e1f54afa9d80e866547 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3590,10 +3590,10 @@ reusify@^1.0.4:
   resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-revolt.js@4.3.3-alpha.7:
-  version "4.3.3-alpha.7"
-  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.7.tgz#de6ecef444e8368aac3753761e2e10f516f50712"
-  integrity sha512-oi76A+EIxrD+tVRTU8s2LISFBpvMf0kpinw5rdukoc1VWpl0bCC6Kko26yC7lhVkWGLTZxHMOKaUkgbOgy0flA==
+revolt.js@4.3.3-alpha.8:
+  version "4.3.3-alpha.8"
+  resolved "https://registry.yarnpkg.com/revolt.js/-/revolt.js-4.3.3-alpha.8.tgz#2a191ffa9d4c304e328b5eb8d9dc1e13e1f99d9a"
+  integrity sha512-A6sjZ7cmeQuqS9otzANv+Rg4CfvpsTMoDARBwQuez4O7NPRopdWNHylUPo20UutAPzW9xoqVbF8673VlTu5Jag==
   dependencies:
     "@insertish/mutable" "1.1.0"
     axios "^0.19.2"