refactor(fe): eliminate every explicit any; enforce no-explicit-any (R7 S3a·4)
Removes all 13 remaining `any`s and flips the ESLint rule from off to error so new ones can't creep back: - api.ts prefs/data JSON bags: Record<string, any> -> Record<string, unknown>, narrowed at consumers (App language guard; NotificationsPanel shapes the notification `data` per type behind its existing typeof guards) - catch (e: any) -> catch (e) + `e instanceof HttpError` narrowing (SettingsPanel, SetupWizard, PlexPlayer) - the YouTube IFrame API boundary: new lib/youtube.ts types (YTPlayer/ YTPlayerEvent/YTNamespace + a Window augmentation) replace the 6 player anys; tsc surfaced the exact method surface to declare - NotificationsPanel `t` props: any-options -> i18next TFunction Gate green: typecheck (app+node+e2e), eslint 0 errors (rule now enforced), prettier, 74 vitest.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useSyncExternalStore } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { TFunction } from "i18next";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { qk } from "../lib/queryKeys";
|
||||
import {
|
||||
@@ -223,7 +224,7 @@ function NotificationRow({
|
||||
onOpenScheduler,
|
||||
}: {
|
||||
n: AppNotification;
|
||||
t: (k: string, o?: any) => string;
|
||||
t: TFunction;
|
||||
onRead: () => void;
|
||||
onDismiss: () => void;
|
||||
onOpenScheduler: () => void;
|
||||
@@ -239,15 +240,18 @@ function NotificationRow({
|
||||
let title = n.title;
|
||||
let body = n.body;
|
||||
if (isMaintenance) {
|
||||
// Guarded above (typeof count === "number"); shape the JSON `data` bag for typed access.
|
||||
const d = n.data as { count: number };
|
||||
title = t("inbox.maintenance.title");
|
||||
body = t("inbox.maintenance.body", { count: n.data!.count });
|
||||
body = t("inbox.maintenance.body", { count: d.count });
|
||||
} else if (isScheduler) {
|
||||
// "<Job label> finished/failed", with the raw result summary as the (technical) body.
|
||||
const job = t(`scheduler.jobs.${n.data!.job_id}`, n.data!.job_id);
|
||||
title = t(n.data!.status === "error" ? "inbox.jobDone.titleError" : "inbox.jobDone.titleOk", {
|
||||
const d = n.data as { job_id: string; status?: string; summary?: string };
|
||||
const job = t(`scheduler.jobs.${d.job_id}`, d.job_id);
|
||||
title = t(d.status === "error" ? "inbox.jobDone.titleError" : "inbox.jobDone.titleOk", {
|
||||
job,
|
||||
});
|
||||
body = n.data!.summary || n.body;
|
||||
body = d.summary || n.body;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
@@ -320,7 +324,7 @@ function ClientActivityRow({
|
||||
onRemove,
|
||||
}: {
|
||||
n: ClientNotif;
|
||||
t: (k: string, o?: any) => string;
|
||||
t: TFunction;
|
||||
onFind: (meta: VideoHiddenMeta | VideoWatchedMeta) => void;
|
||||
onRevert: (meta: VideoHiddenMeta | VideoWatchedMeta) => void;
|
||||
onFocusChannel: (name: string) => void;
|
||||
|
||||
Reference in New Issue
Block a user