Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: lens to get the selected element form a dictionary #188

Open
stijnvn opened this issue Feb 8, 2023 · 1 comment
Open

Question: lens to get the selected element form a dictionary #188

stijnvn opened this issue Feb 8, 2023 · 1 comment

Comments

@stijnvn
Copy link

stijnvn commented Feb 8, 2023

Given the following interface

interface State {
  selectedId: string;
  dictionary: {[key: string]: { foo: string}};
}

How can I build a lens to get/set/modify the selected element (State.dictionary[State.selectedId])?

Can I somehow combine the following lenses? Or how can this be done with monocle-ts?

const selectedIdLens = Lens.fromProp<State>()('selectedId');
const dictionaryLens = Lens.fromProp<State>()('dictionary');
const itemLens = (id: string) => Lens.fromProp<{[key: string]: { foo: string}}>()(id);
@sviridoff
Copy link

sviridoff commented Jun 14, 2023

Hi, if you want to access directly to a specific selectedId you can use fromPath, here an example:

import assert from 'node:assert/strict';
import { Lens } from "monocle-ts";

interface DictionaryItem {
  foo: string;
}

interface State {
  selectedId: string;
  dictionary: Record<string, DictionaryItem>;
}

const state: State = {
  selectedId: '1',
  dictionary: {
    '1': { foo: 'bar' },
    '2': { foo: 'baz' },
  },
};

const result_2 = Lens.fromPath<State>()(['dictionary', state.selectedId, 'foo'])
    .modify((_) => 'baz')(state);

assert.deepStrictEqual(
  result_2,
  {
    selectedId: '1',
    dictionary: {
      '1': { foo: 'baz' },
      '2': { foo: 'baz' },
    },
  }
);

In case you need to traverse unknown keys you can do the following:

import assert from 'node:assert/strict';
import { Lens, Prism, fromTraversable } from "monocle-ts";
import { record } from 'fp-ts/lib/Record';

interface DictionaryItem {
  foo: string;
}

interface State {
  selectedId: string;
  dictionary: Record<string, DictionaryItem>;
}

const state: State = {
  selectedId: '1',
  dictionary: {
    '1': { foo: 'bar' },
    '2': { foo: 'baz' },
  },
};

const result_1 = Lens.fromProp<State>()('dictionary')
    .composeTraversal(fromTraversable(record)<DictionaryItem>())
    .composePrism(Prism.fromPredicate<DictionaryItem>((dictionaryItem) => dictionaryItem.foo === 'bar'))
    .composeLens(Lens.fromProp<DictionaryItem>()('foo'))
    .modify((_) => 'baz')(state);

assert.deepStrictEqual(
  result_1,
  {
    selectedId: '1',
    dictionary: {
      '1': { foo: 'baz' },
      '2': { foo: 'baz' },
    },
  }
);

or finally accessing like you did:

import assert from 'node:assert/strict';
import { Lens } from "monocle-ts";

interface DictionaryItem {
  foo: string;
}

interface State {
  selectedId: string;
  dictionary: Record<string, DictionaryItem>;
}

const state: State = {
  selectedId: '1',
  dictionary: {
    '1': { foo: 'bar' },
    '2': { foo: 'baz' },
  },
};

const result_3 = Lens.fromProp<State>()('dictionary')
  .composeLens(Lens.fromProp<Record<string, DictionaryItem>>()(state.selectedId))
  .composeLens(Lens.fromProp<DictionaryItem>()('foo'))
  .modify((_) => 'baz')(state);

assert.deepStrictEqual(
  result_3,
  {
    selectedId: '1',
    dictionary: {
      '1': { foo: 'baz' },
      '2': { foo: 'baz' },
    },
  }
);

imstead of modify you can use set

hope it helps

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants