From be7e0100d294ba35db5bed03c09ae15beaf3e4d0 Mon Sep 17 00:00:00 2001 From: "Benjamin P. Jones" Date: Tue, 1 Oct 2024 21:07:47 -0400 Subject: [PATCH] Add typings for window. The codebase is littered with (window as any).some_field. This diff applies some types. There are two benefits: - More consistency when storing and accessing fields. - Centralized documentation of the global variables. --- src/components/ChatUserList/ChatUserList.tsx | 2 +- .../ErrorBoundary/ErrorBoundary.tsx | 2 +- src/components/MiniGoban/MiniGoban.tsx | 2 +- .../NetworkStatus/NetworkStatus.tsx | 2 +- .../Notifications/NotificationManager.tsx | 2 +- src/components/TimeControl/util.ts | 4 +- src/lib/configure-goban.tsx | 4 +- src/lib/debug.ts | 2 +- src/lib/hooks.ts | 4 +- src/lib/image_resizer.ts | 2 +- src/lib/misc.ts | 2 +- src/lib/ogsHistory.ts | 2 +- src/lib/report_manager.tsx | 2 +- src/lib/sfx.ts | 6 +- src/lib/sockets.ts | 8 +-- src/lib/swal_config.ts | 2 +- src/lib/toast.tsx | 2 +- src/lib/translate.test.ts | 6 +- src/main.tsx | 25 ++++----- src/views/Game/AIReview.tsx | 2 +- src/views/Game/AntiGrief.tsx | 2 +- src/views/Game/Game.tsx | 6 +- src/views/Joseki/Joseki.tsx | 2 +- src/views/LearningHub/InstructionalGoban.tsx | 2 +- src/views/LearningHub/LearningPage.tsx | 2 +- src/views/Puzzle/Puzzle.tsx | 2 +- src/views/SignIn/SignIn.tsx | 2 +- src/views/Supporter/Supporter.tsx | 2 +- src/views/Tournament/Tournament.tsx | 6 +- .../TournamentRecord/TournamentRecord.tsx | 2 +- typings_manual/index.d.ts | 55 +++++++++++++++++++ 31 files changed, 109 insertions(+), 57 deletions(-) diff --git a/src/components/ChatUserList/ChatUserList.tsx b/src/components/ChatUserList/ChatUserList.tsx index 1ad009c162..2bdfa357c0 100644 --- a/src/components/ChatUserList/ChatUserList.tsx +++ b/src/components/ChatUserList/ChatUserList.tsx @@ -43,7 +43,7 @@ export function ChatUserList(props: ChatUserListProperties): JSX.Element { proxy.current.on("part", () => refresh(proxy?.current?.channel.users_by_name.length || 0)); proxy.current.on("join", () => console.log("JOin!")); proxy.current.on("part", () => console.log("Part!")); - (window as any)["proxy"] = proxy.current; + window.proxy = proxy.current; refresh(proxy.current.channel.users_by_name.length); return () => { diff --git a/src/components/ErrorBoundary/ErrorBoundary.tsx b/src/components/ErrorBoundary/ErrorBoundary.tsx index c44dcb744e..4cecdd90a0 100644 --- a/src/components/ErrorBoundary/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary/ErrorBoundary.tsx @@ -97,7 +97,7 @@ export class ErrorBoundary extends React.Component { } } -(window as any)["test_sentry"] = () => { +window.test_sentry = () => { try { throw new Error("SENTRY TEST"); } catch (e) { diff --git a/src/components/MiniGoban/MiniGoban.tsx b/src/components/MiniGoban/MiniGoban.tsx index 17443c2104..48a6d70766 100644 --- a/src/components/MiniGoban/MiniGoban.tsx +++ b/src/components/MiniGoban/MiniGoban.tsx @@ -140,7 +140,7 @@ export function MiniGoban(props: MiniGobanProps): JSX.Element { } if (props.sampleOptions?.undo) { - (window as any)["mini_goban"] = goban.current; + window.mini_goban = goban.current; //goban.current.visual_undo_request_indicator = true; goban.current.engine.undo_requested = goban.current.engine.cur_move.move_number; } diff --git a/src/components/NetworkStatus/NetworkStatus.tsx b/src/components/NetworkStatus/NetworkStatus.tsx index ff1dcc07d3..f0557e2a74 100644 --- a/src/components/NetworkStatus/NetworkStatus.tsx +++ b/src/components/NetworkStatus/NetworkStatus.tsx @@ -87,7 +87,7 @@ export function NetworkStatus(): JSX.Element | null { in_live_game ? "in live game," : "not in live game,", manually_closed ? "manually closed notification," : "didn't close notification", "time control:", - (window as any)["global_goban"]?.engine?.time_control, + window.global_goban?.engine?.time_control, ); if (state === "connected" || state === "went-away") { diff --git a/src/components/Notifications/NotificationManager.tsx b/src/components/Notifications/NotificationManager.tsx index 70100cdcc0..ed9d80e5b8 100644 --- a/src/components/Notifications/NotificationManager.tsx +++ b/src/components/Notifications/NotificationManager.tsx @@ -198,7 +198,7 @@ export class NotificationManager { event_emitter: TypedEventEmitter; constructor() { - (window as any)["notification_manager"] = this; + window.notification_manager = this; this.event_emitter = new TypedEventEmitter(); this.notifications = {}; diff --git a/src/components/TimeControl/util.ts b/src/components/TimeControl/util.ts index 43356df6b4..56fb812dca 100644 --- a/src/components/TimeControl/util.ts +++ b/src/components/TimeControl/util.ts @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -import { computeAverageMoveTime, GobanRenderer, JGOFTimeControl } from "goban"; +import { computeAverageMoveTime, JGOFTimeControl } from "goban"; import { _, pgettext, ngettext, interpolate } from "@/lib/translate"; import { TimeControl, TimeControlTypes } from "./TimeControl"; @@ -454,7 +454,7 @@ export function usedForCheating(_time_control: ValidTimeControlFormats) { export function lookingAtOurLiveGame(): boolean { // Is the current page looking at a game we are live playing in... - const goban = (window as any)["global_goban"] as GobanRenderer; + const goban = window.global_goban; if (!goban) { return false; } diff --git a/src/lib/configure-goban.tsx b/src/lib/configure-goban.tsx index 1ef5ac7e81..a456868fe5 100644 --- a/src/lib/configure-goban.tsx +++ b/src/lib/configure-goban.tsx @@ -26,8 +26,8 @@ import { Goban, GobanBase, GobanEngine, setGobanRenderer } from "goban"; import { sfx } from "@/lib/sfx"; import { toast } from "@/lib/toast"; -(window as any)["GobanThemes"] = Goban.THEMES; -(window as any)["GobanEngine"] = GobanEngine; +window.GobanThemes = Goban.THEMES; +window.GobanEngine = GobanEngine; let previous_toast: any = null; diff --git a/src/lib/debug.ts b/src/lib/debug.ts index 0dd8b45673..66c25fbfd4 100644 --- a/src/lib/debug.ts +++ b/src/lib/debug.ts @@ -63,4 +63,4 @@ export default class Debug { } } -(window as any)["debug"] = debug; +window.debug = debug; diff --git a/src/lib/hooks.ts b/src/lib/hooks.ts index 594cf9e350..29cd89c979 100644 --- a/src/lib/hooks.ts +++ b/src/lib/hooks.ts @@ -66,8 +66,8 @@ export function useRefresh(): () => void { return React.useCallback(() => refresh(() => Math.random()), [refresh]); } -export function useMainGoban(): Goban | null { - return (window as any)["global_goban"]; +export function useMainGoban(): Goban | null | undefined { + return window.global_goban; } export const useIsDesktop = () => { diff --git a/src/lib/image_resizer.ts b/src/lib/image_resizer.ts index b7e3cdd695..df238c61c5 100644 --- a/src/lib/image_resizer.ts +++ b/src/lib/image_resizer.ts @@ -28,7 +28,7 @@ export function image_resizer( } console.log(file); - (window as any)["file"] = file; + window.file = file; const reader = new FileReader(); const image = new Image(); diff --git a/src/lib/misc.ts b/src/lib/misc.ts index 751cf8e508..6069c9efd1 100644 --- a/src/lib/misc.ts +++ b/src/lib/misc.ts @@ -1193,7 +1193,7 @@ const real_now = Date.now; export function skew_clock(ms: number): void { Date.now = () => real_now() + ms; } -(window as any).skew_clock = skew_clock; +window.skew_clock = skew_clock; /** Returns true if we are running in local development or on a beta site. * False if we are running in production. */ diff --git a/src/lib/ogsHistory.ts b/src/lib/ogsHistory.ts index 375454ad61..da8049eaba 100644 --- a/src/lib/ogsHistory.ts +++ b/src/lib/ogsHistory.ts @@ -18,4 +18,4 @@ import { createBrowserHistory } from "history"; export const browserHistory = createBrowserHistory(); -(window as any)["browserHistory"] = browserHistory; +window.browserHistory = browserHistory; diff --git a/src/lib/report_manager.tsx b/src/lib/report_manager.tsx index 888aab226b..a9cf10ce6e 100644 --- a/src/lib/report_manager.tsx +++ b/src/lib/report_manager.tsx @@ -414,4 +414,4 @@ function compare_reports(a: Report, b: Report): number { export const report_manager = new ReportManager(); -(window as any)["report_manager"] = report_manager; +window.report_manager = report_manager; diff --git a/src/lib/sfx.ts b/src/lib/sfx.ts index 402789db82..d4d466fcf2 100644 --- a/src/lib/sfx.ts +++ b/src/lib/sfx.ts @@ -447,7 +447,7 @@ export class SFXManager { const release_base: string = data.get("config.cdn_release", ""); const howl = new Howl({ src: - (window as any).safari !== undefined // As of safari 14.1, their webm implementation cannot play our webm audio files correctly. + window.safari !== undefined // As of safari 14.1, their webm implementation cannot play our webm audio files correctly. ? [`${release_base}/sound/${sprite_pack.filename_prefix}.mp3`] : [ `${release_base}/sound/${sprite_pack.filename_prefix}.webm`, @@ -630,7 +630,7 @@ export class SFXManager { export { sprite_packs } from "./sfx_sprites"; export const sfx = new SFXManager(); -(window as any)["sfx"] = sfx; +window.sfx = sfx; const I = setInterval(() => { /* postpone downloading stuff till more important things have begun loading */ @@ -643,7 +643,7 @@ const I = setInterval(() => { }, 100); /* Check and warn if we don't have an effect mapping for every sound voice sound */ -(window as any)["sprite_packs"] = sprite_packs; +window.sprite_packs = sprite_packs; const effects = sprite_packs["zz-un-effects"]; for (const pack of [GameVoiceSounds, CountdownSounds, StoneSounds, EffectsSounds]) { for (const name of pack) { diff --git a/src/lib/sockets.ts b/src/lib/sockets.ts index b4d03bb0d4..f8c5fe4675 100644 --- a/src/lib/sockets.ts +++ b/src/lib/sockets.ts @@ -21,7 +21,7 @@ import { lookingAtOurLiveGame } from "@/components/TimeControl/util"; const debug = new Debug("sockets"); -export const socket = new GobanSocket((window as any)["websocket_host"] ?? window.location.origin); +export const socket = new GobanSocket(window.websocket_host ?? window.location.origin); // Updated to be more helpful (shorter) when we know latencies socket.options.ping_interval = 10000; @@ -38,7 +38,7 @@ const MAX_TIMEOUT_DELAY = 14000; export let ai_host = "https://beta-ai.online-go.com"; if ( window.location.hostname.indexOf("dev.beta") >= 0 && - (window as any)["websocket_host"] === "https://online-go.com" + window.websocket_host === "https://online-go.com" ) { // if we're developing locally but connecting to the production system, use our local system for estimation ai_host = `http://localhost:13284`; @@ -97,7 +97,7 @@ socket.on("latency", (latency, drift) => { // If they are playing a live game at the moment, work out what timing they would like // us to make sure that they have... if (lookingAtOurLiveGame()) { - const goban = (window as any)["global_goban"] as GobanRenderer; + const goban = window.global_goban as GobanRenderer; const time_control = goban.engine.time_control as JGOFTimeControl; switch (time_control.system) { case "fischer": @@ -192,4 +192,4 @@ export default { get_network_latency: get_network_latency, }; -(window as any)["socket"] = socket; +window.socket = socket; diff --git a/src/lib/swal_config.ts b/src/lib/swal_config.ts index 60c061f3b6..6e5837a143 100644 --- a/src/lib/swal_config.ts +++ b/src/lib/swal_config.ts @@ -34,4 +34,4 @@ export const alert = Swal.mixin({ allowEscapeKey: true, }); -(window as any)["swal"] = alert; +window.swal = alert; diff --git a/src/lib/toast.tsx b/src/lib/toast.tsx index 9a274dd88a..057220f98c 100644 --- a/src/lib/toast.tsx +++ b/src/lib/toast.tsx @@ -89,4 +89,4 @@ export function toast(element: React.ReactElement, timeout: number = 0): To return ret; } -(window as any)["toast"] = toast; +window.toast = toast; diff --git a/src/lib/translate.test.ts b/src/lib/translate.test.ts index 176fcc04d7..9c15566c4d 100644 --- a/src/lib/translate.test.ts +++ b/src/lib/translate.test.ts @@ -4,8 +4,8 @@ */ // Set the window variables before importing the module -(window as any)["ogs_current_language"] = "test_language"; -(window as any)["ogs_locales"] = { +window.ogs_current_language = "test_language"; +window.ogs_locales = { en: {}, test_language: { msgid_1: ["translation_1"], @@ -16,7 +16,7 @@ "context\u0004singular\u0005plural": ["tr_singular_2", "tr_plural_2"], }, }; -(window as any)["ogs_countries"] = { +window.ogs_countries = { en: { us: "United States" }, test_language: { test_cc: "test_country" }, }; diff --git a/src/main.tsx b/src/main.tsx index b3e7987032..3128c79383 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -121,7 +121,7 @@ import * as preferences from "@/lib/preferences"; try { // default_theme is set in index.html based on looking at the OS theme - data.setDefault("theme", (window as any)["default_theme"]); + data.setDefault("theme", window.default_theme); } catch (e) { data.setDefault("theme", "light"); } @@ -145,16 +145,13 @@ data.setDefault("config", { user: default_user }); data.setDefault("config.user", default_user); -data.setDefault("config.cdn", (window as any)["cdn_service"]); +data.setDefault("config.cdn", window.cdn_service); data.setDefault( "config.cdn_host", - (window as any)["cdn_service"].replace("https://", "").replace("http://", "").replace("//", ""), + window.cdn_service.replace("https://", "").replace("http://", "").replace("//", ""), ); -data.setDefault( - "config.cdn_release", - (window as any)["cdn_service"] + "/" + (window as any)["ogs_release"], -); -data.setDefault("config.release", (window as any)["ogs_release"]); +data.setDefault("config.cdn_release", window.cdn_service + "/" + window.ogs_release); +data.setDefault("config.release", window.ogs_release); configure_goban(); @@ -224,7 +221,7 @@ try { player_cache.update(user); data.set("user", user); -(window as any)["user"] = user; +window.user = user; console.log("initial user", user); /*** @@ -280,7 +277,7 @@ sockets.socket.on("user/update", (user: any) => { data.set("config.user", user); player_cache.update(user); data.set("user", user); - (window as any)["user"] = user; + window.user = user; } else { console.log("Ignoring user update for user", user); } @@ -337,9 +334,9 @@ react_root.render( , ); -(window as any)["data"] = data; -(window as any)["preferences"] = preferences; -(window as any)["player_cache"] = player_cache; +window.data = data; +window.preferences = preferences; +window.player_cache = player_cache; import * as requests from "@/lib/requests"; -(window as any)["requests"] = requests; +window.requests = requests; diff --git a/src/views/Game/AIReview.tsx b/src/views/Game/AIReview.tsx index c8089f195e..cc682a8376 100644 --- a/src/views/Game/AIReview.tsx +++ b/src/views/Game/AIReview.tsx @@ -102,7 +102,7 @@ export class AIReview extends React.Component table_hidden: preferences.get("ai-summary-table-show"), }; this.state = state; - (window as any)["aireview"] = this; + window.aireview = this; } componentDidMount() { diff --git a/src/views/Game/AntiGrief.tsx b/src/views/Game/AntiGrief.tsx index 303110f90a..6521c2d96a 100644 --- a/src/views/Game/AntiGrief.tsx +++ b/src/views/Game/AntiGrief.tsx @@ -38,7 +38,7 @@ let was_player = false; function checkForLeavingLiveGame(pathname: string) { try { const user = data.get("user"); - const goban = (window as any)["global_goban"]; + const goban = window.global_goban; const was_on_page = on_game_page; const was_live_game = live_game; diff --git a/src/views/Game/Game.tsx b/src/views/Game/Game.tsx index 837b16921b..7ff5b716ac 100644 --- a/src/views/Game/Game.tsx +++ b/src/views/Game/Game.tsx @@ -1144,7 +1144,7 @@ export function Game(): JSX.Element | null { goban.current = createGoban(opts); onResize(true); - (window as any)["global_goban"] = goban.current; + window.global_goban = goban.current; if (review_id) { goban.current.setMode("analyze"); } @@ -1617,8 +1617,8 @@ export function Game(): JSX.Element | null { if (autoplay_timer.current) { clearTimeout(autoplay_timer.current); } - (window as any)["Game"] = null; - (window as any)["global_goban"] = null; + window.Game = null; + window.global_goban = null; setExtraActionCallback(null as any); $(window).off("focus", onFocus); diff --git a/src/views/Joseki/Joseki.tsx b/src/views/Joseki/Joseki.tsx index fc522ab376..80443753ae 100644 --- a/src/views/Joseki/Joseki.tsx +++ b/src/views/Joseki/Joseki.tsx @@ -340,7 +340,7 @@ class _Joseki extends React.Component { this.goban = createGoban(opts); this.goban.setMode("puzzle"); this.goban.on("update", () => this.onBoardUpdate()); - (window as any)["global_goban"] = this.goban; + window.global_goban = this.goban; }; componentDidMount = () => { diff --git a/src/views/LearningHub/InstructionalGoban.tsx b/src/views/LearningHub/InstructionalGoban.tsx index 6b61f0dd3e..da04226dc9 100644 --- a/src/views/LearningHub/InstructionalGoban.tsx +++ b/src/views/LearningHub/InstructionalGoban.tsx @@ -90,7 +90,7 @@ export class InstructionalGoban extends React.Component }, this.props.config, ); - (window as any)["goban"] = this.goban; + window.goban = this.goban; this.goban.setMode(this.props.config.mode || "puzzle"); if (this.props.config.engine_phase) { diff --git a/src/views/LearningHub/LearningPage.tsx b/src/views/LearningHub/LearningPage.tsx index 7752f83ceb..9162ca16e1 100644 --- a/src/views/LearningHub/LearningPage.tsx +++ b/src/views/LearningHub/LearningPage.tsx @@ -220,7 +220,7 @@ export abstract class LearningPage extends React.Component { } this.goban = createGoban(opts); this.goban.setMode("puzzle"); - (window as any)["global_goban"] = this.goban; + window.global_goban = this.goban; this.goban.on("update", () => this.onUpdate()); this.goban.on("puzzle-wrong-answer", this.onWrongAnswer); diff --git a/src/views/SignIn/SignIn.tsx b/src/views/SignIn/SignIn.tsx index a1a781e2b9..2187c3587d 100644 --- a/src/views/SignIn/SignIn.tsx +++ b/src/views/SignIn/SignIn.tsx @@ -29,7 +29,7 @@ import { useUser } from "@/lib/hooks"; import { SocialLoginButtons } from "@/components/SocialLoginButtons"; -(window as any)["Md5"] = Md5; +window.Md5 = Md5; import { alert } from "@/lib/swal_config"; import { LoadingButton } from "@/components/LoadingButton"; diff --git a/src/views/Supporter/Supporter.tsx b/src/views/Supporter/Supporter.tsx index f5494b469e..079031b87c 100644 --- a/src/views/Supporter/Supporter.tsx +++ b/src/views/Supporter/Supporter.tsx @@ -154,7 +154,7 @@ function load_checkout_libraries(): void { script.async = true; //script.charset = "utf-8"; script.onload = () => { - (window as any)["stripe"] = stripe = new Stripe(data.get("config")?.stripe_pk); + window.stripe = stripe = new Stripe(data.get("config")?.stripe_pk); resolve(); }; script.onerror = () => { diff --git a/src/views/Tournament/Tournament.tsx b/src/views/Tournament/Tournament.tsx index 21912f3c07..ffa1d645ef 100644 --- a/src/views/Tournament/Tournament.tsx +++ b/src/views/Tournament/Tournament.tsx @@ -852,7 +852,7 @@ export function Tournament(): JSX.Element { } }; - (window as any)["tournament"] = tournament; + window.tournament = tournament; let tournament_time_start_text = ""; if (tournament.time_start) { @@ -2631,7 +2631,7 @@ function OpenGothaRoster({ tournament: TournamentInterface; players: TournamentPlayer[]; }): JSX.Element { - (window as any)["players"] = players; + window.players = players; players.sort((a, b) => a.username.localeCompare(b.username)); return (
@@ -2674,7 +2674,7 @@ function OpenGothaTournamentRound({ const [notes, _set_notes]: [string, (s: string) => void] = React.useState(roundNotes); const [notes_updated, set_notes_updated]: [boolean, (b: boolean) => void] = React.useState(false); - (window as any)["rounds"] = rounds; + window.rounds = rounds; const round_started = !!( rounds.length >= selectedRound && (rounds[selectedRound - 1]?.matches.length || 0) > 0 ); diff --git a/src/views/TournamentRecord/TournamentRecord.tsx b/src/views/TournamentRecord/TournamentRecord.tsx index d00da78151..93a25d5e5e 100644 --- a/src/views/TournamentRecord/TournamentRecord.tsx +++ b/src/views/TournamentRecord/TournamentRecord.tsx @@ -26,7 +26,7 @@ import { ignore, errorAlerter, dup } from "@/lib/misc"; import { rankString, allRanks } from "@/lib/rank_utils"; import { createDemoBoard } from "@/components/ChallengeModal"; -(window as any)["dup"] = dup; +window.dup = dup; import { alert } from "@/lib/swal_config"; const ranks = allRanks(); diff --git a/typings_manual/index.d.ts b/typings_manual/index.d.ts index 4197db68b9..5b904ec253 100644 --- a/typings_manual/index.d.ts +++ b/typings_manual/index.d.ts @@ -1 +1,56 @@ /// + +interface Window { + global_goban?: import("goban").GobanRenderer | null; + // TODO: dedupe with global_goban + goban?: import("goban").GobanRenderer | null; + + // Set in index.html + cdn_service: string; + default_theme: string; + ogs_release: string; + ogs_current_language: string; + + // Set by translation files + ogs_locales: Record>>; + ogs_countries: Record> + + // Set by gulp + websocket_host: string; + + // set in main.tsx + user: unknown; + data: unknown; + preferences: unknown; + player_cache: unknown; + requests: unknown; + + debug: unknown; // debug.ts + socket: unknown; // socket.ts + + // These seem to be part of some very specific debugging. Can any be removed? + mini_goban?: import("goban").GobanRenderer; // MiniGoban + dup: Function; // TournamentRecord.tsx + rounds?: unknown; // Tournament.tsx + players?: unknown; // Tournament.tsx + tournament?: unknown; // Tournament.tsx + file?: unknown; // image_resizer.ts + browserHistory: unknown; // ogsHistory.ts + report_manager: unknown; // report_manager.ts + sfx: unknown; // sfx.ts + sprite_packs: unknown; // sfx.ts + swal: unknown; // swal.ts + toast: Function; // toast.tsx + aireview?: unknown; // AIReview.tsx + stripe?: unknown; // Supporter.tsx + Md5: unknown; // SignIn.tsx + Game?: null; // Game.tsx + GobanThemes: unknown; // configure-goban.ts + GobanEngine: unknown; // configure-goban.ts + skew_clock: Function; // misc.ts + notification_manager?: unknown; // NotificationManager.tsx + test_sentry: Function; // ErrorBoundary.tsx + proxy?: unknown; // ChatUserList.tsx + + safari?: unknown; +} \ No newline at end of file