mirror of
https://github.com/stoatchat/for-legacy-web.git
synced 2026-03-07 01:15:28 +00:00
remove most uses of as any in typescript
- replaced many uses of `as any` with another more specific cast `as T` - filled in missing typed for items that needed to be typed - new runtime code was added where necessary to satisfy the new types with comments - added missing theme variable "sidebar-active" to the Theme variables - forms using `react-hook-form` are now typechecked - changed some instances of `target` into `currentTarget` while removing `as any` assertions
This commit is contained in:
@@ -122,9 +122,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];
|
||||
|
||||
// TOOD: clean this up and use the built in Intl API
|
||||
function transformLanguage(obj: { [key: string]: any }) {
|
||||
const dayjs = obj.dayjs;
|
||||
const defaults = dayjs.defaults;
|
||||
@@ -158,7 +160,7 @@ function Locale({ children, locale }: Props) {
|
||||
|
||||
if (lang.i18n === "hardcore") {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
setDefinition({} as any);
|
||||
setDefinition({});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -30,7 +30,8 @@ export type Variables =
|
||||
| "status-away"
|
||||
| "status-busy"
|
||||
| "status-streaming"
|
||||
| "status-invisible";
|
||||
| "status-invisible"
|
||||
| "sidebar-active";
|
||||
|
||||
export type Theme = {
|
||||
[variable in Variables]: string;
|
||||
@@ -45,7 +46,7 @@ export interface ThemeOptions {
|
||||
}
|
||||
|
||||
// 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",
|
||||
@@ -72,6 +73,7 @@ export const PRESETS: { [key: string]: Theme } = {
|
||||
"status-busy": "#F84848",
|
||||
"status-streaming": "#977EFF",
|
||||
"status-invisible": "#A5A5A5",
|
||||
"sidebar-active": "var(--secondary-background)"
|
||||
},
|
||||
dark: {
|
||||
light: false,
|
||||
@@ -99,6 +101,7 @@ export const PRESETS: { [key: string]: Theme } = {
|
||||
"status-busy": "#F84848",
|
||||
"status-streaming": "#977EFF",
|
||||
"status-invisible": "#A5A5A5",
|
||||
"sidebar-active": "var(--secondary-background)"
|
||||
},
|
||||
};
|
||||
|
||||
@@ -113,7 +116,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;
|
||||
@@ -123,7 +127,7 @@ interface Props {
|
||||
function Theme(props: Props) {
|
||||
const theme: Theme = {
|
||||
...PRESETS["dark"],
|
||||
...(PRESETS as any)[props.options?.preset as any],
|
||||
...PRESETS[props.options?.preset ?? ''],
|
||||
...props.options?.custom
|
||||
};
|
||||
|
||||
|
||||
@@ -33,8 +33,10 @@ export interface VoiceState {
|
||||
participants?: Readonly<Map<string, VoiceUser>>;
|
||||
}
|
||||
|
||||
export const VoiceContext = createContext<VoiceState>(undefined as any);
|
||||
export const VoiceOperationsContext = createContext<VoiceOperations>(undefined as any);
|
||||
// [bree] TODO: I feel like these should be typechecked anyways but whatever,
|
||||
// I'm asserting that they aren't null because they get used near immedietly from what I can tell
|
||||
export const VoiceContext = createContext<VoiceState>(null!);
|
||||
export const VoiceOperationsContext = createContext<VoiceOperations>(null!);
|
||||
|
||||
type Props = {
|
||||
children: Children;
|
||||
|
||||
@@ -119,8 +119,9 @@ export function SpecialInputModal(props: SpecialProps) {
|
||||
question={<Text id="app.settings.permissions.create_role" />}
|
||||
field={<Text id="app.settings.permissions.role_name" />}
|
||||
callback={async name => {
|
||||
// bree: this returns void, dunno why props.callback was being called
|
||||
const role = await client.servers.createRole(props.server, name);
|
||||
props.callback(role.id);
|
||||
// props.callback(role.id);
|
||||
}}
|
||||
/>;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -43,8 +43,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) {
|
||||
|
||||
@@ -34,9 +34,10 @@ 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);
|
||||
// TODO: remove temporary non-null assertions and properly typecheck these as they aren't always immedietely initialized
|
||||
export const AppContext = createContext<Client>(null!);
|
||||
export const StatusContext = createContext<ClientStatus>(null!);
|
||||
export const OperationsContext = createContext<ClientOperations>(null!);
|
||||
|
||||
type Props = WithDispatcher & {
|
||||
auth: AuthState;
|
||||
@@ -93,16 +94,14 @@ function Context({ auth, children, dispatcher }: Props) {
|
||||
const login = () =>
|
||||
dispatcher({
|
||||
type: "LOGIN",
|
||||
session: client.session as any
|
||||
session: client.session! // TODO: verify that this null assertion is correct
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
@@ -23,11 +23,11 @@ type Props = WithDispatcher & {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export function registerEvents({
|
||||
}
|
||||
}
|
||||
|
||||
const listeners = {
|
||||
let listeners: Record<string, (...args: any[]) => void> = {
|
||||
connecting: () =>
|
||||
operations.ready() && setStatus(ClientStatus.CONNECTING),
|
||||
|
||||
@@ -87,21 +87,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) {
|
||||
@@ -135,8 +132,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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user