diff --git a/packages/dataverse/src/Atom.test.ts b/packages/dataverse/src/Atom.test.ts index 2c14065..9120114 100644 --- a/packages/dataverse/src/Atom.test.ts +++ b/packages/dataverse/src/Atom.test.ts @@ -31,6 +31,9 @@ describe(`Atom`, () => { atom.setByPointer((p) => p, {foo: 'newfoo', bar: -1}) expect(atom.get()).toEqual({foo: 'newfoo', bar: -1}) + // `getByPointer()` is to `get()` what `setByPointer()` is to `set()` + expect(atom.getByPointer((p) => p.bar)).toBe(-1) + // `reduceByPointer()` is to `setByPointer()` what `reduce()` is to `set()` atom.reduceByPointer( (p) => p.bar, diff --git a/packages/dataverse/src/pointer.test.ts b/packages/dataverse/src/pointer.test.ts new file mode 100644 index 0000000..7303f68 --- /dev/null +++ b/packages/dataverse/src/pointer.test.ts @@ -0,0 +1,61 @@ +import {pointer, getPointerParts, Atom} from '@theatre/dataverse' + +describe(`pointer`, () => { + test(`Basic useage of pointer`, async () => { + const root = {foo: 'foo', bar: 0} + const p = pointer({root: root, path: []}) + + const parts = getPointerParts(p) + expect(parts.root).toBe(root) + expect(parts.path).toEqual([]) + + const pointerToFoo = p.foo + // p.foo is a pointer to the `foo` property of the root object. its only difference to p is that its path is `['foo']` + expect(getPointerParts(pointerToFoo).path).toEqual(['foo']) + expect(getPointerParts(pointerToFoo).root).toBe(root) + + // subPointers are cached + expect(pointerToFoo).toBe(p.foo) + + // we can also manually construct the pointer to foo: + const pointerToFoo2 = pointer({root: root, path: ['foo']}) + expect(getPointerParts(pointerToFoo2).path).toEqual(['foo']) + }) + + test(`Well-typed pointers`, () => { + type Data = {str: string; foo?: {bar?: {baz: number}}} + const root: Data = {str: 'some string'} + + // pointers bocome useful when we properly type them. Let's do that now: + const p = pointer({ + root, + path: [], + }) + + // or alternatively: `pointer(...) as Pointer` + + // now typescript will error if we try to access a property that doesn't exist + // @ts-expect-error + p.baz + + // but it will not error if we access a property that does exist + p.foo + + // won't get an error when accessing foo.bar.baz + p.foo.bar.baz + + // but will get an error when accessing foo.bar.baz.nonExistentProperty + // @ts-ignore + p.foo.bar.baz.nonExistentProperty + + // we don't need to manually type the pointer since pointers are usually provided by Atoms, and those are already typed + const atom = new Atom(root) + + // so this will be fine by typescript: + atom.pointer.foo.bar.baz + + // while this will error + // @ts-ignore + atom.pointer.foo.bar.baz.nonExistentProperty + }) +})