map function not accepting stream of 'Subjects' - ngrx

I am missing something obvious, but I can't see it
export const subjectSelector: MemoizedSelector<
any,
Subject[]
> = new EntitySelectorsFactory().create<Subject>('subject').selectEntities;
this.store.pipe(
select(entitySelectors.subjectSelector),
map((s:Subject) => return {...s, z: {}}),
filter((subject:Subject) => subject.z.evidence && subject.z.evidence.length > 0)
);
select(entitySelectors.subjectSelector) is returning an array of Subject objects, but the compiler complains
Type 'Subject' is missing the following properties from type 'Subject[]': length, pop, push, concat, and 28 more.
map((s:Subject) => return {...s, z: {}}),
What am I missing?

Seems like you are confusing list and Observable map() function. This works for me assuming selectEntities returns the Ngrx Entity type Dictionary. The Parenthteses are hell though:
this.store.pipe(select(subjectSelector),
map((subjects: Dictionary<Subject>) => Object.values(subjects).map(s => ({...s, z: {}}))));
if 'subjects' is just a plain array, this will do:
this.store.pipe(select(subjectSelector),
map((subjects: Subject[]) => subjects.map(s => ({...s, z: {}}))));

Related

Handelbars find helper return object and assign key value to a template variable

I add a generic helper to find an item in an Array.
module.exports = function(array, findFunctionString) {
const fn = new Function("return" + findFunctionString)();
return array.find(fn)
};
My array is like :
[{label: "foo", selected: true}, {label: "bar", selected: false}]
What I'm looking now is to get the result and assign to a template variable with a specific key of this returned object.
{{#> myTemplate myVar=(find myArray "(el) => el.selected").label}}{{/myTemplate}}
I still got an error
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'SEP'
Yet, if remove ".label", no error, the object is well assigned to myVar. But I just want to assign the value of the key label.
Why can't I access to the key of the returned object ?
The solution was to use in addition lookup helper.
label=(lookup (find data.languageSelector.options "(el => el.selected)") "label")

Generate a predicate out of two predicates (job for monoid, fold?)

I have two predicates
interface Foo {}
interface Bar {}
declare const isFoo: (a:unknown):a is Foo
declare const isBar: (a:unknown):a is Bar
What is the functional way to combine two predicates to create a new predicate (for simplicity, let's assume it's a => isFoo(a) && isBar(a)?
With fp-ts, I initially thought I could fold(monoidAll)([isFoo, isBar]), but fold expects the array to be of booleans, not of functions that evaluate to boolean.
This works
import { monoid as M, function as F, apply as A, identity as I, reader as R } from 'fp-ts'
interface Foo{}
interface Bar{}
declare const isFoo:(a:unknown) => a is Foo
declare const isBar:(a:unknown) => a is Bar
const isFooAndBar = F.pipe(A.sequenceT(R.reader)(isFoo, isBar), R.map(M.fold(M.monoidAll)))
But boy howdy is that convoluted. I thought there could be another way. I ended up writing my own monoid that takes two predicates and combines them, calling it monoidPredicateAll:
const monoidPredicateAll:M.Monoid<Predicate<unknown>> = {
empty: ()=>true,
concat: (x,y) => _ => x(_) && y(_)
}
Is there a canonical FP way of combining two predicates? I know I could do something like
xs.filter(x => isFoo(x) && isBar(x))
But it can get complicated with more predicates, and re-using a monoid makes it less likely I'll do a typo like isFoo(x) || isBar(x) && isBaz(x) when I meant all && (and that's where a xs.filter(fold(monoidPredicateAll)(isFoo,isBar,isBaz)) would help out.
I found a discussion about this on SO, but it was about Java and a built-in Predicate type, so didn't directly address my question.
Yes, I'm overthinking this :)
I ended up doing this:
export const monoidPredicateAll:Monoid<Predicate<unknown>> = {
empty: ()=>true,
concat: (x,y) => _ => x(_) && y(_)
}
Then I could do
import {monoid as M} from 'fp-ts'
declare const isFoo: Predicate<number>
declare const isBar: Predicate<number>
const isFooAndBar = M.fold(monoidPredicateAll)([isFoo,isBar])
For others looking for a working solution, based on #user1713450's answer
import * as P from 'fp-ts/lib/Predicate';
import * as M from 'fp-ts/Monoid';
const createMonoidPredicateAll = <T>(): M.Monoid<P.Predicate<T>> => ({
empty: () => true,
concat: (x, y) => (_) => x(_) && y(_),
});
export const combine = <T>(predicates: P.Predicate<T>[]) =>
M.concatAll(createMonoidPredicateAll<T>())(predicates);

How do I pass in multiple parameters into a Ramda compose chain?

Here are four functions I am trying to compose into a single endpoint string:
const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const params = str => `${str}?sort=desc&part=true&`
const query = str => `${str}query={ some:'value', another:'value'}`
let finalEndpoint = R.compose(query, params, protocol, endpoint)
var result = finalEndpoint('api.content.io')
This composition works and returns the result I want which is:
https://api.content.io?sort=desc&part=true&query={ some:'value', another:'value'}
But notice how I have hard coded the values for params and query inside their function body. I see only one value going up the value in this R.compose chain.
How and where exactly do I pass in parameters to the params and query parameters?
UPDATE:
What I did was curried those functions like this:
var R = require('ramda');
const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const setParams = R.curry ( (str, params) => `${str}?${params}` )
const setQuery = R.curry ( (str, query) => `${str}&query=${JSON.stringify(query)}` )
and then
let finalEndpoint = R.compose(protocol, endpoint)
var result = setQuery(setParams(finalEndpoint('api.content.io'), 'sort=desc&part=true'), { some:'value', another:'value'})
console.log(result);
But the final call to get result still seems pretty hacked and inelegant. Is there any way to improve this?
How and where exactly do I pass in parameters to the params and query parameters?
Honestly, you don't, not when you're building a compose or pipe pipeline with Ramda or similar libraries.
Ramda (disclaimer: I'm one of the authors) allows the first function to receive multiple arguments -- some other libraries do, some don't -- but subsequent ones will only receive the result of the previous calls. There is one function in Sanctuary, meld, which might be helpful with this, but it does have a fairly complex API.
However, I don't really understand why you are building this function in this manner in the first place. Are those intermediate functions actually reusable, or are you building them on spec? The reason I ask is that this seems a more sensible version of the same idea:
const finalEndpoint = useWith(
(endpoint, params, query) =>`https://${endpoint}?${params}&query=${query}`, [
endpoint => endpoint || 'default',
pipe(toPairs, map(join('=')), join('&')),
pipe(JSON.stringify, encodeURIComponent)
]
);
finalEndpoint(
'api.content.io',
{sort: 'desc', part: true},
{some:'value', another:'value'}
);
//=> "https://api.content.io?sort=desc&part=true&query=%7B%22some%22%3A%22value%22%2C%22another%22%3A%22value%22%7D"
I don't really know your requirements for that last parameter. It looked strange to me without that encodeUriComponent, but perhaps you don't need it. And I also took liberties with the second parameter, assuming that you would prefer actual data in the API to a string encapsulating that data. But if you want to pass 'sort=desc&part=true', then replace pipe(toPairs, map(join('=')), join('&')) with identity.
Since the whole thing is far from points-free, I did not use a points-free version of the first function, perhaps or(__, 'default'), as I think what's there is more readable.
Update
You can see a version of this on the Ramda REPL, one that adds some console.log statements with tap.
This does raise an interesting question for Ramda. If those intermediate functions really are desirable, Ramda offers no way to combine them. Obviously Ramda could offer something like meld, but is there a middle ground? I'm wondering if there is a useful function (curried, of course) that we should include that works something like
someFunc([f0], [a0]); //=> f0(a0)
someFunc([f0, f1], [a0, a1]); //=> f1(f0(a0), a1)
someFunc([f0, f1, f2], [a0, a1, a2]); //=> f2(f1(f0(a0), a1), a2)
someFunc([f0, f1, f2, f3], [a0, a1, a2, a3]); //=> f3(f2(f1(f0(a0), a1), a2), a3)
// ...
There are some serious objections: What if the lists are of different lengths? Why is the initial call unary, and should we fix that by adding a separate accumulator parameter to the function? Nonetheless, this is an intriguing function, and I will probably raise it for discussion on the Ramda boards.
I wrote a little helper function for situations like this.
It is like compose, but with the rest params also passed in. The first param is the return value of the previous function. The rest params remain unchanged.
With it, you could rewrite your code as follows:
const compound = require('compound-util')
const endpoint = str => `${str}` || 'default'
const protocol = str => `https://${str}`
const params = (str, { params }) => `${str}?${params}`
const query = (str, { query }) => `${str}query=${query}`
const finalEndpoint = compound(query, params, protocol, endpoint)
const result = finalEndpoint('api.content.io', {
params: 'sort=desc&part=true&',
query: JSON.stringify({ some:'value', another:'value'})
})
If you have params and query as curried functions then you can:
EDIT: code with all the bells and whistles, needed to change parameter order or use R.__ and stringify object
const endpoint = R.curry( str => `${str}` || 'default' )
const protocol = R.curry( str => `https://${str}` )
const params = R.curry( (p, str) => `${str}?${p}` )
const query = R.curry( (q, str) => `${str}&query=${q}` )
let finalEndpoint =
R.compose(
query(JSON.stringify({ some:'value', another:'value' })),
params('sort=desc&part=true'),
protocol,
endpoint
)
var result = finalEndpoint('api.content.io')
console.log(result)

Filtering out maybe types before accessing nullable property

Given these two types:
type Point = [
number,
number,
];
type Some = {
a: Point,
b: ?Point,
};
And the data set:
const somes: Array<Some> = [
{a: [0, 1], b: [0, 2]},
{a: [2, 3], b: null}
]
Flow will automatically fail if we try to access somes[n].b.x given that b is a maybe type and might be either null or undefined.
We can however with confidence filter out all items in somes to exclude any item that does not include b:
const withB = somes.filter(s => !!s.b)
However flowtype will still complain when accessing items in withB as it doesn't pick up the exclusion:
console.log( withB.map(s => s.b[0]).join(',') )
// console.log(withB.map(s => s.b[0]).join(','))
// ^^^^^^ access of computed property/element. // Computed property/element cannot be accessed on possibly undefined value
// console.log(withB.map(s => s.b[0]).join(','))
// ^^^ undefined
Is it possible to somehow annotate or hint to flow that all items in withB are now guaranteed to include the b property?
Another option if you are willing to pay for additional computations
const withB = somes
.map(x => x.b ? { a: x.a, b: x.b } : null)
.filter(Boolean)
Here is the general way to hint Flow anything:
const withB: Array<{ a: Point, b: Point }> = (somes.filter(s => !!s.b): any)
It won't be safe in your case though. You have an array of mutable objects and property 'b' can be set to null at any time.

How to handle polymorphic type for both value and function?

Consider the following type:
declare class Test<T> {
static of(value: T): Test<T>;
map<U>(fn: (value:T) => U): Test<U>;
}
Now for function ap, T is a function and it works like this:
Test.of(x => x * 2)
.ap(Test.of(5))
.map(console.log) // Output(number): 10
Test.of(x => `${x * 2}!`)
.ap(Test.of(5))
.map(console.log) // Output(string): 10!
So, to properly type check ap I need to do ap(Test<[get type of x]>): [type of output of T]
I tried Test<I, O>, where I is optional for values. But, it adds a lots of unnecessary thing to other functions. Is there any better way to solve this?
Note: I'm trying to write type definition for data.task
This is a tricky one! The ap() method can't be called on an instance of Test<T> for all T's, but only when T is a function that takes at most one argument.
So what you really need is something that is still TODO for Flow. It would look like this:
declare class Test<T> {
static of(value: T): Test<T>;
map<U>(fn: (value:T) => U): Test<U>;
ap<I,O>(this: Test<(in: I) => O>, test: Test<I>): Test<O>;
}
It declares that this must be a Test<T> where T is a function that takes I. Here's a GitHub issue about it.
In the meantime, you could do a first order approximation. It would look like this:
declare class Test<T> {
static of<I, O>(fn: (in: I) => O): FuncTest<I, O>;
static of(value: T): Test<T>;
map<U>(fn: (value:T) => U): Test<U>;
}
declare class FuncTest<I, O> extends Test<(in: I) => O> {
ap(x: Test<I>): Test<O>;
}
Test.of(x => x * 2)
.ap(Test.of(5))
.map(x => (x: number)) // no error
Test.of(x => `${x * 2}!`)
.ap(Test.of(5))
.map(x => (x: string)) // no error
Try this example on flowtype.org/try
The downside of this approach is that ap() returns Test<O>, even if O is a function. So you can't call ap() twice.
Test.of(x => Test.of(y => x * y))
.ap(Test.of(5))
.map(x => (x: Test<(y: number) => number>)); // This is fine
Test.of(x => Test.of(y => x * y))
.ap(Test.of(5))
.ap(Test.of(2)) // This is an error :(

Resources