fix(audiobooks): satisfy noUncheckedIndexedAccess in audiobook code

tsc -b runs with noUncheckedIndexedAccess on, so indexed reads must
guard for undefined even when the loop bounds make it provably safe.
Bind the indexed value to a local in findChapterAt and ChaptersSection,
and use non-null assertions in tests where the test data shape makes
the indexed element guaranteed. No runtime change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
RXWatcher
2026-05-25 01:51:39 +02:00
co-authored by Claude Opus 4.7
parent 67fb38f762
commit 32ba81d395
4 changed files with 9 additions and 7 deletions
+3 -2
View File
@@ -39,8 +39,9 @@ function findChapterAt(
seconds: number,
): { label: string; index: number } | null {
for (let i = chapters.length - 1; i >= 0; i--) {
if (seconds >= chapters[i].absoluteStart) {
return { label: chapters[i].label, index: i + 1 };
const ch = chapters[i];
if (ch && seconds >= ch.absoluteStart) {
return { label: ch.label, index: i + 1 };
}
}
return chapters[0] ? { label: chapters[0].label, index: 1 } : null;
@@ -32,13 +32,13 @@ describe("ChaptersSection", () => {
it("sort menu switches between position and longest-first orders", async () => {
render(<ChaptersSection files={files} currentPositionSeconds={null} onSelect={vi.fn()} />);
const rowsBefore = screen.getAllByRole("button", { name: /Prologue|Memory/ });
expect(within(rowsBefore[0]).getByText("Prologue")).toBeInTheDocument();
expect(within(rowsBefore[0]!).getByText("Prologue")).toBeInTheDocument();
await userEvent.click(screen.getByRole("button", { name: /sort/i }));
await userEvent.click(screen.getByRole("menuitem", { name: /longest first/i }));
const rowsAfter = screen.getAllByRole("button", { name: /Prologue|Memory/ });
expect(within(rowsAfter[0]).getByText("Memory")).toBeInTheDocument();
expect(within(rowsAfter[0]!).getByText("Memory")).toBeInTheDocument();
});
it("calls onSelect with absolute start seconds when a chapter is clicked", async () => {
@@ -68,7 +68,8 @@ export function ChaptersSection({ files, currentPositionSeconds, onSelect }: Cha
const currentIndex = useMemo(() => {
if (currentPositionSeconds == null) return -1;
for (let i = rows.length - 1; i >= 0; i--) {
if (currentPositionSeconds >= rows[i].absoluteStart) return i;
const row = rows[i];
if (row && currentPositionSeconds >= row.absoluteStart) return i;
}
return -1;
}, [rows, currentPositionSeconds]);
@@ -41,8 +41,8 @@ describe("useAudiobookPlayback", () => {
useAudiobookPlayback({ contentId: "c", files, initialPositionSeconds: 0 }),
);
expect(result.current.chapters).toHaveLength(2);
expect(result.current.chapters[0].start_seconds).toBe(0);
expect(result.current.chapters[1].start_seconds).toBe(300);
expect(result.current.chapters[0]!.start_seconds).toBe(0);
expect(result.current.chapters[1]!.start_seconds).toBe(300);
});
it("computes streamUrl from the first file id", () => {