From 13a7ae82e340e16e4a4901780aa7d8a1898eb8bd Mon Sep 17 00:00:00 2001 From: LeC-D Date: Thu, 26 Mar 2026 14:07:50 -0400 Subject: [PATCH] fix(notifications): remove type casts with exhaustive type narrowing in useNotificationForm Replace the loose NotificationDefaults intermediate type and 'as NotificationFormData' cast with an exhaustive buildDefaults() helper that narrows each branch of the discriminated union explicitly. TypeScript now infers the return type correctly from the discriminated union without any casts, satisfying strong typing for all channels (email, slack, discord, webhook, pager_duty, teams, matrix, telegram). --- client/src/Hooks/useNotificationForm.ts | 95 ++++++++++++++++--------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/client/src/Hooks/useNotificationForm.ts b/client/src/Hooks/useNotificationForm.ts index deb1db62b..c45773db7 100644 --- a/client/src/Hooks/useNotificationForm.ts +++ b/client/src/Hooks/useNotificationForm.ts @@ -7,41 +7,70 @@ interface UseNotificationFormOptions { data?: Notification | null; } -// Flat defaults type compatible with all form variants for defaultValue props -type NotificationDefaults = { - type: NotificationFormData["type"]; - notificationName: string; - address?: string; - homeserverUrl?: string; - roomId?: string; - accessToken?: string; -}; +function buildDefaults(data: Notification | null): NotificationFormData { + if (data?.type === "matrix") { + return { + type: "matrix", + notificationName: data.notificationName || "", + homeserverUrl: data.homeserverUrl || "", + roomId: data.roomId || "", + accessToken: data.accessToken || "", + }; + } + if (data?.type === "telegram") { + return { + type: "telegram", + notificationName: data.notificationName || "", + address: data.address || "", + accessToken: data.accessToken || "", + }; + } + if (data?.type === "slack") { + return { + type: "slack", + notificationName: data.notificationName || "", + address: data.address || "", + }; + } + if (data?.type === "discord") { + return { + type: "discord", + notificationName: data.notificationName || "", + address: data.address || "", + }; + } + if (data?.type === "webhook") { + return { + type: "webhook", + notificationName: data.notificationName || "", + address: data.address || "", + }; + } + if (data?.type === "pager_duty") { + return { + type: "pager_duty", + notificationName: data.notificationName || "", + address: data.address || "", + }; + } + if (data?.type === "teams") { + return { + type: "teams", + notificationName: data.notificationName || "", + address: data.address || "", + }; + } + // Default: email (covers both data === null and data.type === "email") + return { + type: "email", + notificationName: data?.notificationName || "", + address: data?.address || "", + }; +} export const useNotificationForm = ({ data = null }: UseNotificationFormOptions = {}) => { return useMemo(() => { - let defaults: NotificationDefaults = { - type: (data?.type || "email") as NotificationFormData["type"], - notificationName: data?.notificationName || "", - address: data?.address || "", - }; - - if (data?.type === "matrix") { - defaults = { - type: "matrix", - notificationName: data.notificationName || "", - homeserverUrl: data.homeserverUrl || "", - roomId: data.roomId || "", - accessToken: data.accessToken || "", - }; - } else if (data?.type === "telegram") { - defaults = { - type: "telegram", - notificationName: data.notificationName || "", - address: data.address || "", - accessToken: data.accessToken || "", - }; - } - - return { schema: notificationSchema, defaults: defaults as NotificationFormData }; + const defaults = buildDefaults(data); + return { schema: notificationSchema, defaults }; }, [data]); };