-
-
Notifications
You must be signed in to change notification settings - Fork 4
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
key
lens with a default value
#49
Comments
I've achieved the following with monocle + fp-ts (not fp-ts/optic yet) with the following two functions: export const optionProp = <O, K extends keyof O>(
k: K,
): (<R>(
l: Lens.Lens<R, O>,
) => Lens.Lens<R, O.Option<Exclude<O[K], undefined>>>) =>
Lens.composeLens(
Lens.lens(
(data) =>
pipe(
data[k],
// Note: hasOwnProperty would probably be better here, but this is what I use in my codebase
O.fromPredicate(
(x): x is Exclude<O[K], undefined> => x !== undefined,
),
),
O.fold(
() => (state) => {
const cloned = Object.assign({}, state);
delete cloned[k];
return cloned;
},
(v) => (state) => ({
...state,
[k]: v,
}),
),
),
);
export const non = <T>(
eq: Eq.Eq<T>,
a: T,
): (<U>(l: Lens.Lens<U, O.Option<T>>) => Lens.Lens<U, T>) =>
Lens.composeIso(
Iso.iso(
O.getOrElse(() => a),
O.fromPredicate((x) => !eq.equals(x, a)),
),
); The combination of these allows for pretty flexible use, and allows removal of properties, which your example doesn't. |
@kalda341 Thank you for sharing your code. I've implemented optionProp/non based on your idea and it works great. export const optionProp = <S extends object, Key extends keyof S>(key: Key):
Optic.Lens<S, O.Option<Exclude<S[Key], undefined>>> =>
Optic.lens(
(s) => O.liftPredicate((a): a is Exclude<S[Key], undefined> => a !== undefined)(s[key]),
(a) => (s) =>
O.match({
onNone: () => {
const { ...s1 } = s
delete s1[key]
return s1
},
onSome: (a) => ({ ...s, [key]: a }),
})(a)
)
export const non = <T>(
a: T,
): Optic.Iso<O.Option<T>, T> =>
Optic.iso(
O.getOrElse(() => a),
O.liftPredicate(x => x !== a),
)
type Counters = { [key: string]: { counter: number } }
const c: Counters = { foo: { counter: 1 } }
const _bar = Optic.id<Counters>().compose(optionProp('bar')).compose(non({ counter: 0 })).at('counter') |
🚀 Feature request
Current Behavior
This may be just a newbie question as I'm not familiar with fp-ts or effect-ts library, or the notion of Optics in general...
I want to read and write a property in a nested object that may not exist, as illustrated in the following snippet.
Desired Behavior
Can this be achieved by composing the existing optics in the library, instead of implementing
keyWithDefault
by myself?Suggested Solution
Add an overload of the
key
function that takes a fallback value and returns a lens.Who does this impact? Who is this for?
I suppose using an Object as a dictionary/map is idiomatic in TypeScript/JavaScript and this is useful in many situations.
Describe alternatives you've considered
The proposed function can be easily implemented on the user side as shown in the code snippet. (edited the code; Actually, I happened to know this might not be as easy to implement properly as I think...)
Additional context
Your environment
The text was updated successfully, but these errors were encountered: