{"record":{"id":"45af093ad5a0ff23","repo":"krahets/hello-algo","slug":"the-deque-is-empty-45af09","errorCode":null,"errorMessage":"The Deque Is Empty.","messagePattern":"The Deque Is Empty\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"zh-hant/codes/typescript/chapter_stack_and_queue/array_deque.ts","lineNumber":88,"sourceCode":"    /* 佇列首出列 */\n    popFirst(): number {\n        const num: number = this.peekFirst();\n        // 佇列首指標向後移動一位\n        this.front = this.index(this.front + 1);\n        this.queSize--;\n        return num;\n    }\n\n    /* 佇列尾出列 */\n    popLast(): number {\n        const num: number = this.peekLast();\n        this.queSize--;\n        return num;\n    }\n\n    /* 訪問佇列首元素 */\n    peekFirst(): number {\n        if (this.isEmpty()) throw new Error('The Deque Is Empty.');\n        return this.nums[this.front];\n    }\n\n    /* 訪問佇列尾元素 */\n    peekLast(): number {\n        if (this.isEmpty()) throw new Error('The Deque Is Empty.');\n        // 計算尾元素索引\n        const last = this.index(this.front + this.queSize - 1);\n        return this.nums[last];\n    }\n\n    /* 返回陣列用於列印 */\n    toArray(): number[] {\n        // 僅轉換有效長度範圍內的串列元素\n        const res: number[] = [];\n        for (let i = 0, j = this.front; i < this.queSize; i++, j++) {\n            res[i] = this.nums[this.index(j)];\n        }","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/krahets/hello-algo/blob/69932aed1891a7b7f6a0de88cd116d3fe13e7032/zh-hant/codes/typescript/chapter_stack_and_queue/array_deque.ts#L70-L106","documentation":"An Error 'The Deque Is Empty.' thrown by peekFirst() in ArrayDeque (array_deque.ts:88). peekFirst() returns nums[front], which is meaningless when queSize === 0 because front points at stale or uninitialized data. Both pop methods (popFirst/popLast) call a peek first, so this guard also protects pops from operating on an empty ring buffer.","triggerScenarios":"Calling deque.peekFirst() or deque.popFirst() when deque.isEmpty() is true (queSize === 0). Popping more elements than were pushed, or peeking a deque that was just constructed with `new ArrayDeque(capacity)` and never filled.","commonSituations":"Unbalanced push/pop counts in a ring-buffer deque; assuming a peek is safe because capacity > 0 (capacity is storage size, not element count); draining the deque in a loop without an emptiness check; calling popFirst after popLast already emptied it.","solutions":["Check deque.isEmpty() (or deque.size() === 0) before peekFirst/popFirst.","Loop with `while (!deque.isEmpty())` when draining.","Remember capacity() is the backing array length, not the element count — use size() for the latter.","Keep push and pop counts balanced, or cache the count you intend to consume."],"exampleFix":"// before: peeking an empty deque throws\nconst head = deque.peekFirst();\n\n// after: guard with emptiness check\nconst head = deque.isEmpty() ? undefined : deque.peekFirst();","handlingStrategy":"validation","validationCode":"// Guard the head end of an ArrayDeque\nfunction safePeekFirst(deque: ArrayDeque): number | undefined {\n    return deque.isEmpty() ? undefined : deque.peekFirst();\n}\nif (!deque.isEmpty()) {\n    const head = deque.popFirst();\n}","typeGuard":"const nonEmpty = (deque: ArrayDeque): boolean => !deque.isEmpty();","tryCatchPattern":"try {\n    const head = deque.peekFirst();\n} catch (e) {\n    if (e instanceof Error && /Deque Is Empty/.test(e.message)) {\n        // deque drained; handle empty state\n    } else throw e;\n}","preventionTips":["Check isEmpty() before any peekFirst/popFirst.","Use size() for element count; capacity() is the backing array length.","Keep push and pop counts balanced per session.","Drain with `while (!deque.isEmpty())`."],"tags":["typescript","deque","ring-buffer","empty-collection"],"backgroundTag":null,"analyzedSha":"69932aed1891a7b7f6a0de88cd116d3fe13e7032","analyzedAt":"2026-08-13T23:02:37.581Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}