@oazmi/kitchensink - v0.9.13
    Preparing search index...

    Function mirrorObjectThroughComposition

    • create a new object that mirrors that functionality of an existing object obj, through composition.

      Type Parameters

      • T
      • P extends PropertyKey

      Parameters

      Returns MirrorComposition<T, P>

      import { assertEquals } from "jsr:@std/assert"

      type TypeofB = Array<number> & { getLength(): number }
      type TypeofC = TypeofB & { countZeros(): number }

      const a = Array.prototype
      const b = {
      getLength(): number { return this.length }
      } as TypeofB
      const c = {
      countZeros(): number { return [...this].filter((value) => (value === 0)).length }
      } as TypeofC

      Object.setPrototypeOf(b, a)
      Object.setPrototypeOf(c, b)

      // below, we create an object `d` that mirrors the methods and protperties of `c`, but does not actually inherit it.
      const d = mirrorObjectThroughComposition(c, {
      baseKey: "_super",
      propertyKeys: ["length"],
      })

      // notice that `d` does not inherit `c` as its prototype, despite being able to utilize its methods and properties.
      assertEquals(Object.getPrototypeOf(d), Object.prototype, "`d` does not inherit `c`")

      d.push(0, 0, 0, 0, 1)
      assertEquals([...d], [0, 0, 0, 0, 1], "`d` also mirrors symbolic keys (such as iterators)")
      assertEquals([...c], [0, 0, 0, 0, 1], "mutations made to `d` are applied to `c`")
      assertEquals(d._super, c, "`c` is accessible via the `baseKey` (\"_super\") property")
      assertEquals(d.length, 5)
      assertEquals(c.length, 5)
      assertEquals(d.getLength(), 5)
      assertEquals(d.countZeros(), 4)
      d.splice(0, 3)
      assertEquals(d.countZeros(), 1)
      assertEquals(c.countZeros(), 1)

      // you may even hot-swap the object that is being composed inside of `d`.
      const e = [1, 2, 3, 4, 5, 6, 7, 8, 9]
      Object.setPrototypeOf(e, c)
      d._super = e as TypeofC
      assertEquals(d.length, 9)
      assertEquals(d.getLength(), 9)
      assertEquals(d.countZeros(), 0)

      // it is also possible for you to provide an existing `target` object onto which the mirroring should occur.
      // moreover, you can ignore specific keys which you would like not to be mirrored using the `ignoreKeys` option.
      class F {
      methodF() { return "press f for your fallen comrades" }
      // to stop typescript from complaining, we declare the instance methods and properties that will be mirrored.
      declare _super: typeof c
      declare length: number
      declare getLength: undefined
      declare countZeros: () => number
      }
      mirrorObjectThroughComposition(c, {
      target: F.prototype,
      baseKey: "_super",
      propertyKeys: ["length"],
      ignoreKeys: ["getLength"],
      })
      const f = new F()
      assertEquals(f instanceof F, true)
      assertEquals(f._super, c)
      assertEquals(f.length, 2)
      assertEquals(f.countZeros(), 1)
      assertEquals(f.getLength, undefined) // the `getLength` is not mirrored because it was present in the `ignoreKeys` option
      assertEquals(f.methodF(), "press f for your fallen comrades")