From 8a8138f5461fbd51e3a2faa2a70526ec5f1e6477 Mon Sep 17 00:00:00 2001 From: Matt Phillips Date: Sat, 12 Nov 2022 13:04:17 +0000 Subject: [PATCH] WIP: Add better type definitions --- index.ts | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 index.ts diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..58fc4cd --- /dev/null +++ b/index.ts @@ -0,0 +1,94 @@ +type Diff = { + [Key in keyof A]?: A[Key] extends Array ? Record> : Diff; +}; + +interface DetailedDiff { + added: AddedDiff; + deleted: DeletedDiff; + updated: UpdatedDiff; +} + +// Should return arrays as optional dictionaries with an optional keypath to the array as an item could have been added +// Should return any new keys with non-optional path to the new value +type AddedDiff = { + [Key in keyof R]: Key extends keyof L + ? L[Key] extends R[Key] + ? [L[Key], R[Key]] extends [Array, Array] + ? Record> | undefined + : [L[Key], R[Key]] extends [object, object] + ? AddedDiff | undefined + : never + : AddedDiff + : R[Key]; +}; + +// Should return arrays as optional dictionaries with an optional keypath to the array as an item could have been removed +// Should return any deleted keys with non-optional path to the key +type DeletedDiff = { + [Key in keyof L]: Key extends keyof R + ? R[Key] extends L[Key] + ? [L[Key], R[Key]] extends [Array, Array] + ? Record> | undefined + : [L[Key], R[Key]] extends [object, object] + ? DeletedDiff | undefined + : never + : DeletedDiff + : undefined; +}; + +// TODO: Implement this diff +type UpdatedDiff = {}; + +declare function diff(originalObj: L, updatedObj: R): Diff & Diff; + +declare function addedDiff(originalObj: L, updatedObj: R): AddedDiff; + +declare function deletedDiff(originalObj: L, updatedObj: R): DeletedDiff; + +declare function updatedDiff(originalObj: L, updatedObj: R): UpdatedDiff; + +declare function detailedDiff(originalObj: L, updatedObj: R): DetailedDiff; + +// ----------------------------------------- Testing playground below + +const lhs = { + foo: { + bar: { + a: ["a", "b"], + b: 2, + c: ["x", "y"], + e: 100, // deleted, + }, + }, + buzz: "world", + numberOrBoolean: 1, + phillips: "name", +}; +type LHS = typeof lhs; + +const rhs = { + foo: { + bar: { + a: ["a"], // index 1 ('b') deleted + b: 2, // unchanged + c: ["x", "y", "z"], // 'z' added + d: "Hello, world!", // added + }, + }, + buzz: "fizz", // updated, + numberOrBoolean: false, + newlyadded: 1, +}; +type RHS = typeof rhs; + +const difference = diff(lhs, rhs); +// TODO: This shouldn't be undefined +difference.numberOrBoolean; + +const added = addedDiff(lhs, rhs); +const deleted = deletedDiff(lhs, rhs); + +// TODO: Test how this algo works for optionals keys on the left and matching optional/required keys on the right +type TestDiff = Diff["foo"]; +type TestAddedDiff = AddedDiff; +type TestDeletedDiff = DeletedDiff["foo"]["bar"];