From 50b7a8a3fd09e879777be4d0989c0378fb8baee7 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 20 Aug 2021 10:34:06 -0700 Subject: [PATCH] Add a comment explaining CursorIterator --- src/matrix/storage/idb/utils.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/matrix/storage/idb/utils.ts b/src/matrix/storage/idb/utils.ts index 83686864..ae2bd03f 100644 --- a/src/matrix/storage/idb/utils.ts +++ b/src/matrix/storage/idb/utils.ts @@ -127,6 +127,23 @@ export function txnAsPromise(txn): Promise { }); } +/** + * This type is rather complicated, but I hope that this is for a good reason. There + * are currently two uses for `iterateCursor`: iterating a regular cursor, and iterating + * a key-only cursor, which does not have values. These two uses are distinct, and iteration + * never stops or starts having a value halfway through. + * + * Each of the argument functions currently either assumes the value will be there, or that it won't. We thus can't + * just accept a function argument `(T | undefined) => { done: boolean }`, since this messes with + * the type safety in both cases: the former case will have to check for `undefined`, and + * the latter would have an argument that can be `T`, even though it never will. + * + * So the approach here is to let TypeScript infer and accept (via generics) the type of + * the cursor, which is either `IDBCursorWithValue` or `IDBCursor`. Since the type is accepted + * via generics, we can actually vary the types of the actual function arguments depending on it. + * Thus, when a value is available (an `IDBCursorWithValue` is given), we require a function `(T) => ...`, and when it is not, we require + * a function `(undefined) => ...`. + */ type CursorIterator = I extends IDBCursorWithValue ? (value: T, key: IDBValidKey, cursor: IDBCursorWithValue) => { done: boolean, jumpTo?: IDBValidKey } : (value: undefined, key: IDBValidKey, cursor: IDBCursor) => { done: boolean, jumpTo?: IDBValidKey }