From 2b9ffc0b62bef7139b210a50f933fd2e2d3cac31 Mon Sep 17 00:00:00 2001 From: Chris Parsons Date: Sat, 21 Mar 2026 09:30:59 -0700 Subject: [PATCH] Fix no-explicit-any warnings and upgrade tsconfig to ES2023 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace all `any` types with proper types or `unknown` across ~20 files - Add typed socket payload interfaces in draft route and useDraftSocket - Use any[] with eslint-disable for socket.io callbacks (legitimate escape hatch) - Bump all tsconfigs from ES2022 → ES2023 to support toSorted/toReversed - Fix cascading type errors uncovered by removing any: Map.get narrowing, participant relation types, ChartDataPoint, Partial indexing - Add ParticipantResultWithParticipant type to participant-result model - Fix test fixtures to match updated interfaces (DraftCell, ParticipantResult) - Fix duplicate getQPStandings import in sportsSeasonId.server.ts Co-Authored-By: Claude Sonnet 4.6 --- app/components/DraftGrid.tsx | 9 ++- app/components/__tests__/DraftGrid.test.tsx | 12 +-- .../sport-season/RegularSeasonStandings.tsx | 2 +- app/hooks/useDraftSocket.ts | 8 +- app/models/participant-result.ts | 5 +- app/models/scoring-event.ts | 3 +- app/models/standings.ts | 4 +- ...sons.$id.events.$eventId.bracket.server.ts | 2 + ...ts-seasons.$id.events.$eventId.bracket.tsx | 26 +++--- ...min.sports-seasons.$id.events.$eventId.tsx | 6 +- .../admin.sports-seasons.$id.events.tsx | 2 +- app/routes/admin.sports-seasons.$id.tsx | 6 +- app/routes/admin.sports-seasons.new.tsx | 8 +- app/routes/api/webhooks/clerk.ts | 8 +- .../$leagueId.draft-board.$seasonId.tsx | 15 ++-- .../leagues/$leagueId.draft.$seasonId.tsx | 81 ++++++++++--------- app/routes/leagues/$leagueId.settings.tsx | 10 +-- ...d.sports-seasons.$sportsSeasonId.server.ts | 18 +++-- ...eagueId.sports-seasons.$sportsSeasonId.tsx | 24 +++--- app/routes/leagues/new.tsx | 2 +- app/routes/test-socket.tsx | 2 +- .../__tests__/probability-updater.test.ts | 5 ++ .../simulations/auto-racing-simulator.ts | 2 +- app/services/simulations/ucl-simulator.ts | 2 +- app/services/standings-sync/nba.ts | 2 +- app/test/setup.ts | 2 +- database/context.browser-stub.ts | 2 +- server/app.ts | 6 +- server/socket.ts | 14 ++-- tsconfig.node.json | 4 +- tsconfig.server.json | 4 +- tsconfig.vite.json | 2 +- 32 files changed, 167 insertions(+), 131 deletions(-) diff --git a/app/components/DraftGrid.tsx b/app/components/DraftGrid.tsx index 4411e1c..71c30f0 100644 --- a/app/components/DraftGrid.tsx +++ b/app/components/DraftGrid.tsx @@ -6,6 +6,13 @@ import { ContextMenuTrigger, } from "~/components/ui/context-menu"; +interface DraftCell { + pickNumber: number; + participant: { id: string; name: string }; + sport: { id: string; name: string }; + team: { id: string; name: string }; +} + interface DraftGridProps { draftSlots: Array<{ id: string; @@ -15,7 +22,7 @@ interface DraftGridProps { name: string; }; }>; - draftGrid: any[][]; + draftGrid: Array>; currentPick: number; teamTimers?: Record; formatTime?: (seconds: number | undefined) => string; diff --git a/app/components/__tests__/DraftGrid.test.tsx b/app/components/__tests__/DraftGrid.test.tsx index 97d64ac..a7f069d 100644 --- a/app/components/__tests__/DraftGrid.test.tsx +++ b/app/components/__tests__/DraftGrid.test.tsx @@ -6,12 +6,12 @@ import { mockDraftSlots } from '~/test/fixtures/team'; describe('DraftGrid Component', () => { const mockGrid = [ [ - { participant: { name: 'Player 1' }, sport: { name: 'NFL' } }, + { pickNumber: 1, participant: { id: 'p1', name: 'Player 1' }, sport: { id: 's1', name: 'NFL' }, team: { id: 't1', name: 'Team 1' } }, null, ], [ null, - { participant: { name: 'Player 2' }, sport: { name: 'NBA' } }, + { pickNumber: 4, participant: { id: 'p2', name: 'Player 2' }, sport: { id: 's2', name: 'NBA' }, team: { id: 't2', name: 'Team 2' } }, ], ]; @@ -143,12 +143,12 @@ describe('DraftGrid Component', () => { it('should reverse picks on even rounds', () => { const snakeGrid = [ [ - { participant: { name: 'Pick 1' }, sport: { name: 'NFL' } }, - { participant: { name: 'Pick 2' }, sport: { name: 'NBA' } }, + { pickNumber: 1, participant: { id: 'p1', name: 'Pick 1' }, sport: { id: 's1', name: 'NFL' }, team: { id: 't1', name: 'Team 1' } }, + { pickNumber: 2, participant: { id: 'p2', name: 'Pick 2' }, sport: { id: 's2', name: 'NBA' }, team: { id: 't2', name: 'Team 2' } }, ], [ - { participant: { name: 'Pick 4' }, sport: { name: 'MLB' } }, - { participant: { name: 'Pick 3' }, sport: { name: 'NHL' } }, + { pickNumber: 3, participant: { id: 'p3', name: 'Pick 4' }, sport: { id: 's1', name: 'MLB' }, team: { id: 't2', name: 'Team 2' } }, + { pickNumber: 4, participant: { id: 'p4', name: 'Pick 3' }, sport: { id: 's2', name: 'NHL' }, team: { id: 't1', name: 'Team 1' } }, ], ]; diff --git a/app/components/sport-season/RegularSeasonStandings.tsx b/app/components/sport-season/RegularSeasonStandings.tsx index d294a9d..765b069 100644 --- a/app/components/sport-season/RegularSeasonStandings.tsx +++ b/app/components/sport-season/RegularSeasonStandings.tsx @@ -26,7 +26,7 @@ interface StandingRow { lastTen: string | null; homeRecord: string | null; awayRecord: string | null; - syncedAt: string | null; + syncedAt: Date | string | null; participant: { id: string; name: string; shortName?: string | null }; } diff --git a/app/hooks/useDraftSocket.ts b/app/hooks/useDraftSocket.ts index 37f2bee..1daf146 100644 --- a/app/hooks/useDraftSocket.ts +++ b/app/hooks/useDraftSocket.ts @@ -9,9 +9,11 @@ interface UseDraftSocketReturn { /** Increments each time a new socket instance is created. Include in * useEffect deps so handler effects re-register on socket recreation. */ socketVersion: number; + // eslint-disable-next-line typescript/no-explicit-any -- socket.io callbacks are untyped at the hook level on: (event: string, callback: (...args: any[]) => void) => void; + // eslint-disable-next-line typescript/no-explicit-any off: (event: string, callback?: (...args: any[]) => void) => void; - emit: (event: string, ...args: any[]) => void; + emit: (event: string, ...args: unknown[]) => void; } export function useDraftSocket(seasonId: string, teamId?: string): UseDraftSocketReturn { @@ -131,15 +133,17 @@ export function useDraftSocket(seasonId: string, teamId?: string): UseDraftSocke // has run (socketRef.current === null) are silently no-ops. Consumers should // only call them inside their own useEffect, not during render or synchronously // after mount. + // eslint-disable-next-line typescript/no-explicit-any -- socket.io callbacks are untyped at the hook level const on = useCallback((event: string, callback: (...args: any[]) => void) => { socketRef.current?.on(event, callback); }, []); + // eslint-disable-next-line typescript/no-explicit-any const off = useCallback((event: string, callback?: (...args: any[]) => void) => { socketRef.current?.off(event, callback); }, []); - const emit = useCallback((event: string, ...args: any[]) => { + const emit = useCallback((event: string, ...args: unknown[]) => { socketRef.current?.emit(event, ...args); }, []); diff --git a/app/models/participant-result.ts b/app/models/participant-result.ts index a893664..72691fe 100644 --- a/app/models/participant-result.ts +++ b/app/models/participant-result.ts @@ -3,6 +3,9 @@ import { database } from "~/database/context"; import * as schema from "~/database/schema"; export type ParticipantResult = typeof schema.participantResults.$inferSelect; +export type ParticipantResultWithParticipant = ParticipantResult & { + participant: { id: string; name: string } | null; +}; export type NewParticipantResult = typeof schema.participantResults.$inferInsert; export async function createParticipantResult( @@ -62,7 +65,7 @@ export async function findParticipantResultByParticipantId( export async function findParticipantResultsBySportsSeasonId( sportsSeasonId: string -): Promise { +): Promise { const db = database(); return await db.query.participantResults.findMany({ where: eq(schema.participantResults.sportsSeasonId, sportsSeasonId), diff --git a/app/models/scoring-event.ts b/app/models/scoring-event.ts index d92f222..b4c2db1 100644 --- a/app/models/scoring-event.ts +++ b/app/models/scoring-event.ts @@ -157,7 +157,7 @@ export async function updateScoringEvent( ) { const db = providedDb || database(); - const updateData: any = { updatedAt: new Date() }; + const updateData: Partial = { updatedAt: new Date() }; if (data.name !== undefined) updateData.name = data.name; if (data.eventDate !== undefined) { @@ -450,6 +450,7 @@ export async function getUpcomingEventsForDraftedParticipants( inArray(schema.playoffMatches.participant1Id, draftedIds), // participant2Id is nullable UUID — same underlying type as participant1Id; // the notNull difference only exists at the TypeScript layer + // oxlint-disable-next-line typescript/no-explicit-any -- participant2Id is nullable UUID; notNull difference only exists at the TypeScript layer // eslint-disable-next-line @typescript-eslint/no-explicit-any inArray(schema.playoffMatches.participant2Id as any, draftedIds) ), diff --git a/app/models/standings.ts b/app/models/standings.ts index a838733..c7b64b3 100644 --- a/app/models/standings.ts +++ b/app/models/standings.ts @@ -402,7 +402,7 @@ export async function getSeasonPointProgression( }); // Organize data by date - const dateMap = new Map(); + const dateMap = new Map(); for (const snapshot of snapshots) { const date = snapshot.snapshotDate; @@ -411,7 +411,7 @@ export async function getSeasonPointProgression( dateMap.set(date, { date }); } - const dateData = dateMap.get(date); + const dateData = dateMap.get(date)!; dateData[snapshot.team.name] = parseFloat(snapshot.totalPoints); } diff --git a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts index d80554a..1ce9a01 100644 --- a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts +++ b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.server.ts @@ -79,6 +79,8 @@ export async function loader({ params }: Route.LoaderArgs) { participant2: { id: string; name: string } | null; winner: { id: string; name: string } | null; loser: { id: string; name: string } | null; + games: Array<{ id: string; gameNumber: number; scheduledAt: Date | null; status: string; winner?: { name: string } | null }>; + odds: Array<{ id: string; participantId: string; moneylineOdds: number; impliedProbability: string; oddsSource?: string | null; participant: { id: string; name: string } | null }>; }>, tournamentGroups, }; diff --git a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.tsx b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.tsx index b8e9190..aff3ba8 100644 --- a/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.tsx +++ b/app/routes/admin.sports-seasons.$id.events.$eventId.bracket.tsx @@ -151,8 +151,8 @@ export default function EventBracket({ const knockoutPopulated = useMemo(() => { if (!isGroupStageEvent) return false; // Check if any Round of 32 match has participants assigned - const r32Matches = matches.filter((m: any) => m.round === "Round of 32"); - return r32Matches.some((m: any) => m.participant1Id || m.participant2Id); + const r32Matches = matches.filter((m) => m.round === "Round of 32"); + return r32Matches.some((m) => m.participant1Id || m.participant2Id); }, [isGroupStageEvent, matches]); // Group stage stats @@ -161,7 +161,7 @@ export default function EventBracket({ let eliminated = 0; let total = 0; for (const group of tournamentGroups) { - for (const member of (group as any).members || []) { + for (const member of group.members || []) { total++; if (member.eliminated) eliminated++; } @@ -174,7 +174,7 @@ export default function EventBracket({ if (!isGroupStageEvent) return []; const advancing: Array<{ id: string; name: string }> = []; for (const group of tournamentGroups) { - for (const member of (group as any).members || []) { + for (const member of group.members || []) { if (!member.eliminated && member.participant) { advancing.push({ id: member.participant.id, @@ -258,7 +258,7 @@ export default function EventBracket({ const getPendingWinnersInRound = (round: string) => { return Object.entries(selectedWinners) .filter(([matchId]) => { - const match = matches.find((m: any) => m.id === matchId); + const match = matches.find((m) => m.id === matchId); return match && match.round === round && !match.isComplete; }); }; @@ -283,7 +283,7 @@ export default function EventBracket({ // Check if all matches are complete const allMatchesComplete = useMemo(() => { - return matches.length > 0 && matches.every((m: any) => m.isComplete); + return matches.length > 0 && matches.every((m) => m.isComplete); }, [matches]); // No bracket and no groups yet = setup phase @@ -685,13 +685,13 @@ export default function EventBracket({ {/* Group Cards */}
- {tournamentGroups.map((group: any) => ( + {tournamentGroups.map((group) => ( Group {group.groupName} - {(group.members || []).map((member: any) => ( + {(group.members || []).map((member) => (
{/* Existing games */} - {(match as any).games?.length > 0 ? ( + {match.games?.length > 0 ? (
- {(match as any).games.map((game: any) => ( + {match.games.map((game) => (
Game {game.gameNumber} @@ -987,7 +987,7 @@ export default function EventBracket({ type="number" min={1} max={9} - defaultValue={((match as any).games?.length ?? 0) + 1} + defaultValue={(match.games?.length ?? 0) + 1} className="h-8 w-20" required /> @@ -1014,9 +1014,9 @@ export default function EventBracket({ Moneyline Odds
- {(match as any).odds?.length > 0 ? ( + {match.odds?.length > 0 ? (
- {(match as any).odds.map((odd: any) => ( + {match.odds.map((odd) => (
{odd.participant?.name} 0 ? "text-emerald-500" : "text-muted-foreground"}`}> diff --git a/app/routes/admin.sports-seasons.$id.events.$eventId.tsx b/app/routes/admin.sports-seasons.$id.events.$eventId.tsx index 1f91c87..ac4bda0 100644 --- a/app/routes/admin.sports-seasons.$id.events.$eventId.tsx +++ b/app/routes/admin.sports-seasons.$id.events.$eventId.tsx @@ -695,12 +695,12 @@ export default function EventResults({ {[...participantResults] - .toSorted((a: any, b: any) => { + .toSorted((a: { finalPosition?: number | null }, b: { finalPosition?: number | null }) => { const posA = a.finalPosition ?? 999; const posB = b.finalPosition ?? 999; return posA - posB; }) - .map((result: any) => ( + .map((result) => (
@@ -730,7 +730,7 @@ export default function EventResults({
- {result.participant.name} + {result.participant?.name} {result.qualifyingPoints ? ( diff --git a/app/routes/admin.sports-seasons.$id.events.tsx b/app/routes/admin.sports-seasons.$id.events.tsx index 4105428..151bb95 100644 --- a/app/routes/admin.sports-seasons.$id.events.tsx +++ b/app/routes/admin.sports-seasons.$id.events.tsx @@ -71,7 +71,7 @@ export default function SportsSeasonEvents({ if (eventType === "schedule_event") { const isPast = eventStartsAt ? new Date(eventStartsAt) < new Date() - : eventDate !== null && eventDate < new Date().toISOString().split("T")[0]; + : eventDate !== null && eventDate !== undefined && eventDate < new Date().toISOString().split("T")[0]; return isPast ? ( Results Pending ) : ( diff --git a/app/routes/admin.sports-seasons.$id.tsx b/app/routes/admin.sports-seasons.$id.tsx index d8f2422..b6a19a7 100644 --- a/app/routes/admin.sports-seasons.$id.tsx +++ b/app/routes/admin.sports-seasons.$id.tsx @@ -3,7 +3,7 @@ import { getAuth } from "@clerk/react-router/server"; import { isUserAdminByClerkId } from "~/models/user"; import type { Route } from "./+types/admin.sports-seasons.$id"; -import { findSportsSeasonById, updateSportsSeason, deleteSportsSeason } from "~/models/sports-season"; +import { findSportsSeasonById, updateSportsSeason, deleteSportsSeason, type NewSportsSeason } from "~/models/sports-season"; import { processSeasonStandings, recalculateStandings } from "~/models/scoring-calculator"; import { createDailySnapshot } from "~/models/standings"; import { database } from "~/database/context"; @@ -252,7 +252,7 @@ export async function action(args: Route.ActionArgs) { } try { - const updateData: any = { + const updateData: Partial = { name: name.trim(), year: yearNum, startDate: typeof startDate === "string" && startDate ? startDate : null, @@ -263,7 +263,7 @@ export async function action(args: Route.ActionArgs) { }; if (scoringPattern && typeof scoringPattern === "string") { - updateData.scoringPattern = scoringPattern; + updateData.scoringPattern = scoringPattern as "playoff_bracket" | "season_standings" | "qualifying_points"; } if (totalMajors && typeof totalMajors === "string") { diff --git a/app/routes/admin.sports-seasons.new.tsx b/app/routes/admin.sports-seasons.new.tsx index 52bf0f7..701cd4d 100644 --- a/app/routes/admin.sports-seasons.new.tsx +++ b/app/routes/admin.sports-seasons.new.tsx @@ -1,7 +1,7 @@ import { Form, Link, redirect } from "react-router"; import type { Route } from "./+types/admin.sports-seasons.new"; -import { createSportsSeason } from "~/models/sports-season"; +import { createSportsSeason, type NewSportsSeason } from "~/models/sports-season"; import { findAllSports } from "~/models/sport"; import { Button } from "~/components/ui/button"; import { Input } from "~/components/ui/input"; @@ -75,7 +75,7 @@ export async function action({ request }: Route.ActionArgs) { } try { - const seasonData: any = { + const seasonData: Partial = { sportId, name: name.trim(), year: yearNum, @@ -86,7 +86,7 @@ export async function action({ request }: Route.ActionArgs) { }; if (scoringPattern && typeof scoringPattern === "string") { - seasonData.scoringPattern = scoringPattern; + seasonData.scoringPattern = scoringPattern as "playoff_bracket" | "season_standings" | "qualifying_points"; } if (totalMajors && typeof totalMajors === "string") { @@ -96,7 +96,7 @@ export async function action({ request }: Route.ActionArgs) { } } - await createSportsSeason(seasonData); + await createSportsSeason(seasonData as NewSportsSeason); return redirect("/admin/sports-seasons"); } catch (error) { diff --git a/app/routes/api/webhooks/clerk.ts b/app/routes/api/webhooks/clerk.ts index 448ac85..da7adb4 100644 --- a/app/routes/api/webhooks/clerk.ts +++ b/app/routes/api/webhooks/clerk.ts @@ -26,7 +26,7 @@ export async function action({ request }: Route.ActionArgs) { // Create a new Svix instance with your webhook secret const wh = new Webhook(WEBHOOK_SECRET); - let evt: any; + let evt: { type: string; data: { id: string; email_addresses?: Array<{ email_address: string }>; username?: string; first_name?: string; last_name?: string; image_url?: string } }; // Verify the webhook try { @@ -34,7 +34,7 @@ export async function action({ request }: Route.ActionArgs) { "svix-id": svix_id, "svix-timestamp": svix_timestamp, "svix-signature": svix_signature, - }); + }) as typeof evt; } catch (err) { console.error("Error verifying webhook:", err); return new Response("Error: Verification failed", { status: 400 }); @@ -53,7 +53,7 @@ export async function action({ request }: Route.ActionArgs) { const user = await findOrCreateUser({ id, emailAddresses: - email_addresses?.map((e: any) => ({ + email_addresses?.map((e: { email_address: string }) => ({ emailAddress: e.email_address, })) || [], username, @@ -69,7 +69,7 @@ export async function action({ request }: Route.ActionArgs) { const user = await findOrCreateUser({ id, emailAddresses: - email_addresses?.map((e: any) => ({ + email_addresses?.map((e: { email_address: string }) => ({ emailAddress: e.email_address, })) || [], username, diff --git a/app/routes/leagues/$leagueId.draft-board.$seasonId.tsx b/app/routes/leagues/$leagueId.draft-board.$seasonId.tsx index 3caa1bc..edd450e 100644 --- a/app/routes/leagues/$leagueId.draft-board.$seasonId.tsx +++ b/app/routes/leagues/$leagueId.draft-board.$seasonId.tsx @@ -127,9 +127,11 @@ export default function DraftBoard() { useEffect(() => { if (season.status !== "draft") return; - const handlePickMade = (data: any) => { - setPicks((prev: any) => [...prev, data.pick]); - setCurrentPick(data.nextPickNumber); + type PickShape = (typeof initialPicks)[number]; + const handlePickMade = (data: unknown) => { + const pickData = data as { pick: PickShape; nextPickNumber: number }; + setPicks((prev) => [...prev, pickData.pick]); + setCurrentPick(pickData.nextPickNumber); }; on("pick-made", handlePickMade); @@ -142,13 +144,14 @@ export default function DraftBoard() { // Generate draft grid const totalTeams = draftSlots.length; const totalRounds = season.draftRounds || 1; - const draftGrid: any[][] = []; + type PickItem = (typeof initialPicks)[number]; + const draftGrid: Array> = []; for (let round = 0; round < totalRounds; round++) { - const roundPicks: any[] = []; + const roundPicks: Array = []; for (let teamIndex = 0; teamIndex < totalTeams; teamIndex++) { const pickNumber = round * totalTeams + teamIndex + 1; - const pick = picks.find((p: any) => p.pickNumber === pickNumber); + const pick = picks.find((p) => p.pickNumber === pickNumber); roundPicks.push(pick || null); } draftGrid.push(roundPicks); diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx index a0a9094..3ee1996 100644 --- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx +++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx @@ -79,7 +79,7 @@ export async function loader(args: Route.LoaderArgs) { // Resolve user's team and commissioner status (null userId means neither) const userTeam = userId - ? season.teams.find((team: any) => team.ownerId === userId) + ? season.teams.find((team) => team.ownerId === userId) : undefined; const isCommissioner = userId @@ -427,7 +427,7 @@ export default function DraftRoom() { // (deduplicated by ID) after the DB snapshot lands. const revalidatorStateRef = useRef(revalidatorState); const isRevalidatingRef = useRef(false); - const pendingPicksDuringRevalidationRef = useRef([]); + const pendingPicksDuringRevalidationRef = useRef<(typeof draftPicks)[number][]>([]); // Track the draftPicks reference when revalidation starts. If it hasn't // changed by the time revalidation completes, the loader didn't return new // data (e.g. network failure) and we should NOT overwrite state that may @@ -467,9 +467,9 @@ export default function DraftRoom() { return; } - const dbPickIds = new Set(draftPicks.map((p: any) => p.id)); + const dbPickIds = new Set(draftPicks.map((p) => p.id)); const missedPicks = pendingPicksDuringRevalidationRef.current.filter( - (p: any) => !dbPickIds.has(p.id) + (p) => !dbPickIds.has(p.id) ); pendingPicksDuringRevalidationRef.current = []; @@ -496,7 +496,7 @@ export default function DraftRoom() { if (timers.length > 0) { setTeamTimers((prev) => { const updated = { ...prev }; - timers.forEach((timer: any) => { + timers.forEach((timer) => { updated[timer.teamId] = timer.timeRemaining; }); return updated; @@ -506,7 +506,7 @@ export default function DraftRoom() { // we were away. setAutodraftStatus(() => { const status: Record = {}; - autodraftSettings.forEach((setting: any) => { + autodraftSettings.forEach((setting) => { status[setting.teamId] = { isEnabled: setting.isEnabled, mode: setting.mode, @@ -547,7 +547,7 @@ export default function DraftRoom() { // Track autodraft status for all teams const [autodraftStatus, setAutodraftStatus] = useState>(() => { const status: Record = {}; - autodraftSettings.forEach((setting: any) => { + autodraftSettings.forEach((setting) => { status[setting.teamId] = { isEnabled: setting.isEnabled, mode: setting.mode, @@ -567,7 +567,7 @@ export default function DraftRoom() { if (timers.length > 0) { // Draft has started, use actual timers - timers.forEach((timer: any) => { + timers.forEach((timer) => { timersMap[timer.teamId] = timer.timeRemaining; }); } else { @@ -610,7 +610,7 @@ export default function DraftRoom() { // Shared transforms for eligibility calculations const transformedPicks = useMemo( () => - picks.map((p: any) => ({ + picks.map((p) => ({ teamId: p.team.id, participant: { id: p.participant.id, @@ -622,7 +622,7 @@ export default function DraftRoom() { const transformedParticipants = useMemo( () => - availableParticipants.map((p: any) => ({ + availableParticipants.map((p) => ({ id: p.id, sport: { id: p.sport.id, name: p.sport.name }, })), @@ -645,7 +645,7 @@ export default function DraftRoom() { const eligibility = useMemo(() => { if (!userTeam) return null; const userTeamPicks = transformedPicks.filter( - (p: any) => p.teamId === userTeam.id + (p) => p.teamId === userTeam.id ); return calculateDraftEligibility( userTeam.id, @@ -662,7 +662,7 @@ export default function DraftRoom() { const forcePickEligibility = useMemo(() => { if (!selectedPickSlot) return null; const selectedTeamPicks = transformedPicks.filter( - (p: any) => p.teamId === selectedPickSlot.teamId + (p) => p.teamId === selectedPickSlot.teamId ); return calculateDraftEligibility( selectedPickSlot.teamId, @@ -679,10 +679,10 @@ export default function DraftRoom() { const replacePickEligibility = useMemo(() => { if (!replacePickSlot) return null; const allPicksExcluding = transformedPicks.filter( - (p: any) => p.participant.id !== replacePickSlot.oldParticipantId + (p) => p.participant.id !== replacePickSlot.oldParticipantId ); const selectedTeamPicks = allPicksExcluding.filter( - (p: any) => p.teamId === replacePickSlot.teamId + (p) => p.teamId === replacePickSlot.teamId ); return calculateDraftEligibility( replacePickSlot.teamId, @@ -697,7 +697,8 @@ export default function DraftRoom() { // Listen for new picks from other users useEffect(() => { - const handlePickMade = (data: any) => { + type PickMadePayload = { pick: (typeof draftPicks)[number] & { team?: { id?: string; name?: string }; participant?: { name?: string } }; nextPickNumber: number; isDraftComplete?: boolean }; + const handlePickMade = (data: PickMadePayload) => { if (isRevalidatingRef.current) { // Buffer this pick; the revalidation-complete handler will merge it // into the DB snapshot so it isn't silently dropped. @@ -706,7 +707,7 @@ export default function DraftRoom() { // pick counter and the picks list in sync with each other. pendingPicksDuringRevalidationRef.current.push(data.pick); } else { - setPicks((prev: any) => [...prev, data.pick]); + setPicks((prev) => [...prev, data.pick]); setCurrentPick(data.nextPickNumber); } @@ -735,7 +736,7 @@ export default function DraftRoom() { } }; - const handleTimerUpdate = (data: any) => { + const handleTimerUpdate = (data: { teamId: string; timeRemaining: number; currentPickNumber: number | null }) => { // Bail out without creating a new object reference if nothing changed. // Without this guard the spread `{ ...prev }` always returns a new object, // causing a full re-render of the DraftRoom tree on every 1-second tick. @@ -819,35 +820,35 @@ export default function DraftRoom() { }; const handleParticipantRemovedFromQueues = (data: { participantId: string }) => { - setQueue((prev: any) => - prev.filter((item: any) => item.participantId !== data.participantId) + setQueue((prev) => + prev.filter((item) => item.participantId !== data.participantId) ); }; const handleQueueEligibilityPruned = (data: { teamId: string; removedParticipantIds: string[] }) => { if (data.teamId !== userTeam?.id) return; const removed = new Set(data.removedParticipantIds); - setQueue((prev: any) => prev.filter((item: any) => !removed.has(item.participantId))); + setQueue((prev) => prev.filter((item) => !removed.has(item.participantId))); }; // Fired when another window/session changes the user's queue (add/remove/reorder/clear). // Only received by this team's own sockets (emitted to team-${teamId} private room). // Ignored while this window has in-flight mutations to prevent the server echo // from clobbering a more-recent optimistic update. - const handleQueueUpdated = (data: { queue: any[] }) => { + const handleQueueUpdated = (data: { queue: QueueItem[] }) => { if (pendingQueueMutationsRef.current > 0) return; setQueue(data.queue); }; - const handlePickReplaced = (data: any) => { - setPicks((prev: any) => - prev.map((p: any) => (p.pickNumber === data.pickNumber ? data.pick : p)) + const handlePickReplaced = (data: { pickNumber: number; pick: (typeof draftPicks)[number] }) => { + setPicks((prev) => + prev.map((p) => (p.pickNumber === data.pickNumber ? data.pick : p)) ); }; - const handleDraftRolledBack = (data: any) => { - setPicks((prev: any) => - prev.filter((p: any) => p.pickNumber < data.pickNumber) + const handleDraftRolledBack = (data: { pickNumber: number }) => { + setPicks((prev) => + prev.filter((p) => p.pickNumber < data.pickNumber) ); setCurrentPick(data.pickNumber); setIsDraftComplete(false); @@ -857,7 +858,7 @@ export default function DraftRoom() { // Full state sync sent by the server on join-draft. Provides an immediate, // socket-based path to bring the client up to date — critical for mobile // reconnection where the HTTP revalidation may be delayed or fail entirely. - const handleDraftStateSync = (data: any) => { + const handleDraftStateSync = (data: { picks: (typeof draftPicks)[number][]; currentPickNumber: number; isPaused: boolean; status: string; timers?: Array<{ teamId: string; timeRemaining: number }>; queue?: QueueItem[] }) => { // If a revalidation is in-flight, let it complete and handle the merge. // The revalidation path already buffers picks and deduplicates — layering // this on top would risk conflicts. But if NOT revalidating, apply the @@ -872,7 +873,7 @@ export default function DraftRoom() { if (data.timers) { setTeamTimers((prev) => { const updated = { ...prev }; - data.timers.forEach((t: any) => { + data.timers?.forEach((t) => { updated[t.teamId] = t.timeRemaining; }); return updated; @@ -1214,7 +1215,7 @@ export default function DraftRoom() { }; const handleReplacePickOpen = useCallback((pickNumber: number, teamId: string) => { - const pick = picks.find((p: any) => p.pickNumber === pickNumber); + const pick = picks.find((p) => p.pickNumber === pickNumber); if (!pick) { toast.error("Pick not found — try refreshing the page"); return; @@ -1387,7 +1388,7 @@ export default function DraftRoom() { round: number; pickInRound: number; teamId: string; - pick?: any; + pick?: (typeof draftPicks)[number]; }> > = []; @@ -1401,7 +1402,7 @@ export default function DraftRoom() { const pickNumber = (round - 1) * teamCount + pickInRound; const teamId = draftSlots[teamIndex]?.team.id; - const pick = picks.find((p: any) => p.pickNumber === pickNumber); + const pick = picks.find((p) => p.pickNumber === pickNumber); roundPicks.push({ pickNumber, round, pickInRound, teamId, pick }); } @@ -1413,7 +1414,7 @@ export default function DraftRoom() { // Get drafted participant IDs for filtering const draftedParticipantIds = useMemo( - () => new Set(picks.map((p: any) => p.participant.id)), + () => new Set(picks.map((p) => p.participant.id)), [picks] ); @@ -1422,8 +1423,8 @@ export default function DraftRoom() { if (!userTeam) return new Set(); return new Set( picks - .filter((p: any) => p.team.id === userTeam.id) - .map((p: any) => p.sport.id) + .filter((p) => p.team.id === userTeam.id) + .map((p) => p.sport.id) ); }, [picks, userTeam]); @@ -1432,8 +1433,8 @@ export default function DraftRoom() { if (!userTeam) return new Set(); return new Set( picks - .filter((p: any) => p.team.id === userTeam.id) - .map((p: any) => p.sport.name) + .filter((p) => p.team.id === userTeam.id) + .map((p) => p.sport.name) ); }, [picks, userTeam]); @@ -1441,7 +1442,7 @@ export default function DraftRoom() { const uniqueSports = useMemo( () => Array.from( - new Set(availableParticipants.map((p: any) => p.sport.name)) + new Set(availableParticipants.map((p) => p.sport.name)) ).sort(), [availableParticipants] ); @@ -1449,7 +1450,7 @@ export default function DraftRoom() { // Filter participants based on search, sport, drafted status, and eligibility const filteredParticipants = useMemo(() => { const sportFilterSet = new Set(sportFilters); - return availableParticipants.filter((participant: any) => { + return availableParticipants.filter((participant) => { // Drafted filter - hide drafted participants by default if (hideDrafted && draftedParticipantIds.has(participant.id)) { return false; @@ -1958,7 +1959,7 @@ export default function DraftRoom() { Roll Back Draft {rollbackPickNumber !== null && (() => { - const count = picks.filter((p: any) => p.pickNumber >= rollbackPickNumber).length; + const count = picks.filter((p) => p.pickNumber >= rollbackPickNumber).length; return `This will erase ${count} pick${count === 1 ? "" : "s"} (pick #${rollbackPickNumber} through the most recent) and return the draft to pick #${rollbackPickNumber}. This cannot be undone.`; })()} diff --git a/app/routes/leagues/$leagueId.settings.tsx b/app/routes/leagues/$leagueId.settings.tsx index 0d89fc9..c5ccf2e 100644 --- a/app/routes/leagues/$leagueId.settings.tsx +++ b/app/routes/leagues/$leagueId.settings.tsx @@ -13,7 +13,7 @@ import { countCommissionersByLeagueId, removeCommissionerByLeagueAndUser, } from "~/models/commissioner"; -import { findCurrentSeasonWithSports, updateSeason } from "~/models/season"; +import { findCurrentSeasonWithSports, updateSeason, type NewSeason } from "~/models/season"; import { findTeamsBySeasonId, deleteTeam, removeTeamOwner, claimTeam } from "~/models/team"; import { findAllUsers, findUserByClerkId, findUsersByClerkIds, getUserDisplayName, isUserAdminByClerkId } from "~/models/user"; import { unlinkSportFromSeason, linkMultipleSportsToSeason } from "~/models/season-sport"; @@ -281,7 +281,7 @@ export async function action(args: Route.ActionArgs) { const selectedSports = formData.getAll("sportsSeasons"); const currentSportIds = new Set( - season.seasonSports?.map((s: any) => s.sportsSeason.id) || [] + season.seasonSports?.map((s) => s.sportsSeason.id) || [] ); const newSportIds = new Set(selectedSports as string[]); @@ -465,7 +465,7 @@ export async function action(args: Route.ActionArgs) { // Now handle season-specific updates. try { // Update season settings - const seasonUpdates: any = {}; + const seasonUpdates: Partial = {}; // Handle draft rounds if (typeof draftRounds === "string") { @@ -514,7 +514,7 @@ export async function action(args: Route.ActionArgs) { if (points < 0 || points > 1000) { return { error: `${field} must be between 0 and 1000 points` }; } - seasonUpdates[field] = points; + (seasonUpdates as Record)[field] = points; } } } @@ -652,7 +652,7 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false); const [timerMode, setTimerMode] = useState<"chess_clock" | "standard">(season?.draftTimerMode ?? "chess_clock"); const [selectedSports, setSelectedSports] = useState>( - new Set(season?.seasonSports?.map((s: any) => s.sportsSeason.id) || []) + new Set(season?.seasonSports?.map((s) => s.sportsSeason.id) || []) ); const [draftOrderTeams, setDraftOrderTeams] = useState( draftSlots.length > 0 diff --git a/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.server.ts b/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.server.ts index 05ba516..32c8ea3 100644 --- a/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.server.ts +++ b/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.server.ts @@ -18,6 +18,7 @@ import { import { getRegularSeasonStandings } from "~/models/regular-season-standings"; import { getAllParticipantEVsForSeason } from "~/models/participant-expected-value"; import { getBracketTemplate, getOrderedRoundsFromMatches } from "~/lib/bracket-templates"; +import type { PlayoffMatch } from "~/models/playoff-match"; import { database } from "~/database/context"; import * as schema from "~/database/schema"; import { eq, and, inArray } from "drizzle-orm"; @@ -136,13 +137,20 @@ export async function loader(args: Route.LoaderArgs) { type SeasonStanding = { id: string; position: number; championshipPoints: string; participant: { id: string; name: string } }; - let playoffMatches: any[] = []; + type PlayoffMatchWithRelations = PlayoffMatch & { + participant1: { id: string; name: string } | null; + participant2: { id: string; name: string } | null; + winner: { id: string; name: string } | null; + loser: { id: string; name: string } | null; + }; + let playoffMatches: PlayoffMatchWithRelations[] = []; let playoffRounds: string[] = []; let preEliminatedParticipants: { id: string; name: string }[] = []; let participantPoints: { participantId: string; points: number }[] = []; let partialScoreParticipantIds: string[] = []; let seasonStandings: SeasonStanding[] = []; - let qpStandings: any[] = []; + type QPStanding = Awaited>[number]; + let qpStandings: QPStanding[] = []; if (scoringPattern === "playoff_bracket") { // Fetch playoff matches via scoring events @@ -164,7 +172,7 @@ export async function loader(args: Route.LoaderArgs) { loser: true, }, }); - playoffMatches = matches; + playoffMatches = matches as PlayoffMatchWithRelations[]; templateId = events.find((e) => e.bracketTemplateId)?.bracketTemplateId ?? undefined; const template = templateId ? getBracketTemplate(templateId) : undefined; @@ -186,8 +194,8 @@ export async function loader(args: Route.LoaderArgs) { ]); preEliminatedParticipants = eliminatedResults - .filter((r) => r.participant) - .map((r) => ({ id: (r as any).participant.id, name: (r as any).participant.name })); + .filter((r): r is typeof r & { participant: NonNullable } => r.participant !== null && r.participant !== undefined) + .map((r) => ({ id: r.participant.id, name: r.participant.name })); // Compute per-participant fantasy points directly from participant_results. // This covers both finalized placements and progressive floor scores for still-alive participants. diff --git a/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.tsx b/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.tsx index 34e13ac..de9df24 100644 --- a/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.tsx +++ b/app/routes/leagues/$leagueId.sports-seasons.$sportsSeasonId.tsx @@ -69,7 +69,7 @@ export default function SportSeasonDetail({ const hasBracket = playoffMatches && playoffMatches.length > 0; const hasStandings = regularSeasonStandings && regularSeasonStandings.length > 0; - const showOtLosses = hasStandings && regularSeasonStandings.some((s: any) => s.otLosses !== null); + const showOtLosses = hasStandings && regularSeasonStandings.some((s) => s.otLosses !== null); const simulatorType = sportsSeason.sport?.simulatorType; const standingsDisplayMode = @@ -80,7 +80,7 @@ export default function SportSeasonDetail({ // Build ownership map for RegularSeasonStandings const ownershipMap = Object.fromEntries( - teamOwnerships.map((o: any) => [ + teamOwnerships.map((o) => [ o.participantId, { teamName: o.teamName, ownerName: o.ownerName ?? "", teamId: o.teamId }, ]) @@ -113,12 +113,12 @@ export default function SportSeasonDetail({ {hasStandings && !hasBracket && (
@@ -129,25 +129,25 @@ export default function SportSeasonDetail({ (upcomingEvents.length > 0 || recentEvents.length > 0) && (
)} {/* Hide bracket display when standings exist but no bracket matches have been set yet */} {!(scoringPattern === "playoff_bracket" && hasStandings && !hasBracket) &&
diff --git a/app/routes/leagues/new.tsx b/app/routes/leagues/new.tsx index ffa6b56..99b7167 100644 --- a/app/routes/leagues/new.tsx +++ b/app/routes/leagues/new.tsx @@ -57,7 +57,7 @@ export async function loader() { return { ...template, sportsSeasonIds: templateWithSports?.seasonTemplateSports?.map( - (ts: any) => ts.sportsSeason.id + (ts: { sportsSeason: { id: string } }) => ts.sportsSeason.id ) || [] }; }) diff --git a/app/routes/test-socket.tsx b/app/routes/test-socket.tsx index 9e7736a..e0048bb 100644 --- a/app/routes/test-socket.tsx +++ b/app/routes/test-socket.tsx @@ -11,7 +11,7 @@ export default function TestSocket() { useEffect(() => { // Listen for test messages - const handleTestMessage = (data: any) => { + const handleTestMessage = (data: unknown) => { console.log("Received test message:", data); setMessages((prev) => [...prev, JSON.stringify(data)]); }; diff --git a/app/services/__tests__/probability-updater.test.ts b/app/services/__tests__/probability-updater.test.ts index c1388ed..4187802 100644 --- a/app/services/__tests__/probability-updater.test.ts +++ b/app/services/__tests__/probability-updater.test.ts @@ -37,6 +37,7 @@ describe("probability-updater", () => { notes: null, createdAt: new Date(), updatedAt: new Date(), + participant: null, }, ]); @@ -108,6 +109,7 @@ describe("probability-updater", () => { notes: null, createdAt: new Date(), updatedAt: new Date(), + participant: null, }, { id: "result-2", @@ -119,6 +121,7 @@ describe("probability-updater", () => { notes: null, createdAt: new Date(), updatedAt: new Date(), + participant: null, }, ]); @@ -195,6 +198,7 @@ describe("probability-updater", () => { notes: null, createdAt: new Date(), updatedAt: new Date(), + participant: null, }, ]); @@ -219,6 +223,7 @@ describe("probability-updater", () => { notes: null, createdAt: new Date(), updatedAt: new Date(), + participant: null, }, ]); diff --git a/app/services/simulations/auto-racing-simulator.ts b/app/services/simulations/auto-racing-simulator.ts index b9c7ba6..0aec9db 100644 --- a/app/services/simulations/auto-racing-simulator.ts +++ b/app/services/simulations/auto-racing-simulator.ts @@ -140,7 +140,7 @@ export class AutoRacingSimulator implements Simulator { for (const p of participants) { const ev = evMap.get(p.id); - rawProbs.set(p.id, ev?.sourceOdds !== null ? americanToImpliedProb(ev.sourceOdds) : fallbackProb); + rawProbs.set(p.id, ev !== undefined && ev.sourceOdds !== null && ev.sourceOdds !== undefined ? americanToImpliedProb(ev.sourceOdds) : fallbackProb); } // Normalize to remove vig diff --git a/app/services/simulations/ucl-simulator.ts b/app/services/simulations/ucl-simulator.ts index 7af4a11..c5af2db 100644 --- a/app/services/simulations/ucl-simulator.ts +++ b/app/services/simulations/ucl-simulator.ts @@ -178,7 +178,7 @@ export class UCLSimulator implements Simulator { const ev = evMap.get(id); rawProbs.set( id, - ev?.sourceOdds !== null ? americanToImpliedProb(ev.sourceOdds) : fallbackProb + ev !== undefined && ev.sourceOdds !== null && ev.sourceOdds !== undefined ? americanToImpliedProb(ev.sourceOdds) : fallbackProb ); } const rawSum = [...rawProbs.values()].reduce((a, b) => a + b, 0); diff --git a/app/services/standings-sync/nba.ts b/app/services/standings-sync/nba.ts index c6933c0..01de825 100644 --- a/app/services/standings-sync/nba.ts +++ b/app/services/standings-sync/nba.ts @@ -122,7 +122,7 @@ export class NbaStandingsAdapter implements StandingsSyncAdapter { // Seed within conference — ESPN key is "playoffSeed", value is a float (1.0, 2.0 ...) const playoffSeedStat = sm.get("playoffSeed"); const conferenceRank = - playoffSeedStat?.value !== null + playoffSeedStat !== undefined && playoffSeedStat.value !== null && playoffSeedStat.value !== undefined ? Math.round(playoffSeedStat.value) : playoffSeedStat?.displayValue ? parseInt(playoffSeedStat.displayValue, 10) || undefined diff --git a/app/test/setup.ts b/app/test/setup.ts index d3d665c..b0b66f6 100644 --- a/app/test/setup.ts +++ b/app/test/setup.ts @@ -13,7 +13,7 @@ process.env.NODE_ENV = 'test'; // Mock Clerk vi.mock('@clerk/react-router/server', () => ({ getAuth: vi.fn(() => Promise.resolve({ userId: 'test-user-id' })), - clerkMiddleware: vi.fn(() => (req: any, res: any, next: any) => next()), + clerkMiddleware: vi.fn(() => (req: unknown, res: unknown, next: () => void) => next()), rootAuthLoader: vi.fn(() => Promise.resolve({ userId: 'test-user-id' })), })); diff --git a/database/context.browser-stub.ts b/database/context.browser-stub.ts index 10f8101..391e6e3 100644 --- a/database/context.browser-stub.ts +++ b/database/context.browser-stub.ts @@ -2,7 +2,7 @@ // The real implementation uses Node.js AsyncLocalStorage which is server-only. // This stub is used during the client build to avoid bundling server-only code. -export const DatabaseContext = null as any; +export const DatabaseContext = null as unknown; export function database(): never { throw new Error("database() can only be called on the server"); diff --git a/server/app.ts b/server/app.ts index 970e972..4ba0fd7 100644 --- a/server/app.ts +++ b/server/app.ts @@ -2,6 +2,7 @@ import { createRequestHandler } from "@react-router/express"; import { drizzle } from "drizzle-orm/postgres-js"; import express from "express"; import postgres from "postgres"; +import type { ServerBuild } from "react-router"; import { RouterContextProvider } from "react-router"; import { DatabaseContext } from "~/database/context"; @@ -18,11 +19,12 @@ app.use((_, __, next) => DatabaseContext.run(db, next)); app.use( createRequestHandler({ - build: () => import("virtual:react-router/server-build") as any, + build: () => import("virtual:react-router/server-build") as unknown as Promise, + // @ts-ignore -- RouterContextProvider is the correct runtime type but tsconfig.server.json can't resolve the conditional type statically getLoadContext() { const provider = new RouterContextProvider(); provider.set(expressValueContext, "Hello from Express"); - return provider as any; // Type assertion needed - RouterContextProvider is the context + return provider as unknown as RouterContextProvider; }, }), ); diff --git a/server/socket.ts b/server/socket.ts index cd63296..c44fe8a 100644 --- a/server/socket.ts +++ b/server/socket.ts @@ -21,12 +21,12 @@ function getSocketDb(): PostgresJsDatabase { // Socket event types interface ServerToClientEvents { "test-message": (data: { - originalMessage: any; + originalMessage: unknown; serverResponse: string; serverTimestamp: string; socketId: string; }) => void; - "pick-made": (data: any) => void; + "pick-made": (data: unknown) => void; "draft-started": (data: { seasonId: string; currentPickNumber: number }) => void; "draft-completed": () => void; "timer-update": (data: { @@ -59,9 +59,9 @@ interface ServerToClientEvents { round: number; pickInRound: number; timeUsed: number; - team: any; - participant: any; - sport: any; + team: unknown; + participant: unknown; + sport: unknown; }>; timers: Array<{ teamId: string; @@ -80,7 +80,7 @@ interface ServerToClientEvents { interface ClientToServerEvents { "join-draft": (seasonId: string, teamId?: string) => void; "leave-draft": (seasonId: string) => void; - "test-event": (data: any) => void; + "test-event": (data: unknown) => void; } // Global type augmentation @@ -274,7 +274,7 @@ export function initializeSocketIO(httpServer: HTTPServer): SocketIOServer { } }); - socket.on("test-event", (data: any) => { + socket.on("test-event", (data: unknown) => { console.log("📨 Received test-event from client:", socket.id, data); socket.emit("test-message", { diff --git a/tsconfig.node.json b/tsconfig.node.json index 903976f..549fec1 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -17,8 +17,8 @@ "composite": true, "strict": true, "types": ["node"], - "lib": ["ES2022"], - "target": "ES2022", + "lib": ["ES2023"], + "target": "ES2023", "module": "ES2022", "moduleResolution": "bundler" } diff --git a/tsconfig.server.json b/tsconfig.server.json index 0b746f2..189f35c 100644 --- a/tsconfig.server.json +++ b/tsconfig.server.json @@ -5,10 +5,10 @@ "noEmit": false, "outDir": "./dist/server", "rootDir": ".", - "target": "ES2022", + "target": "ES2023", "module": "ES2022", "moduleResolution": "node", - "lib": ["ES2022"], + "lib": ["ES2023"], "types": ["node"], "strict": true, "esModuleInterop": true, diff --git a/tsconfig.vite.json b/tsconfig.vite.json index 65c39fb..bb8cff9 100644 --- a/tsconfig.vite.json +++ b/tsconfig.vite.json @@ -14,7 +14,7 @@ "compilerOptions": { "composite": true, "strict": true, - "lib": ["DOM", "DOM.Iterable", "ES2022"], + "lib": ["DOM", "DOM.Iterable", "ES2023"], "types": ["vite/client"], "target": "ES2022", "module": "ES2022",