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).
This commit is contained in:
LeC-D committed 2026-03-26 14:07:50 -04:00
1 parent 4c94a7c21e
commit 13a7ae82e3
1 file changed
+62 -33
+62 -33
View File
@@ -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]);
};