Handelbars find helper return object and assign key value to a template variable - handlebars.js

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")

Related

What is the name of Symfony function for "fancy array_merge()"?

I remember I read about it somewhere in the docs and saw it being used in the code, but can't remember its name. It was described as "fancy way of doing array_merge()" or something. It allowed to merge two arrays with parameters and included some simple type checking.
function doSomething ($params) {
$defaultParams = [
'foo' => false,
'bar' => 1,
];
$p = whatsTheFunctionName($params, $defaultParams, [/* foo is bool, bar is int */]);
}
I think you're looking for the OptionsResolver component: "improved replacement for the array_replace PHP function".
See: https://symfony.com/doc/current/components/options_resolver.html

How do I specify a type for a function parameter that optionally includes a given method?

Updated Question
I want to define a function named bsearch() to do binary searches against arrays of arbitrary object types. When I invoke the function, I want it to check whether or not the Type of the array contains a compare() method and use it, if it does. If it does not, I want it to fall back to using < and === (so it will work with strings and numbers).
What should the function declaration look like? (I don't need an actual implementation, just the syntax for a type-safe solution.)
Or maybe I'm going about this all wrong? How can I create a function that uses a method built into a parameter type if it exists, or use some other function when it doesn't?
Original Question
This is the original question, but I've replaced it with the above as it seems this wasn't getting my point across.
I want to define a function named bsearch() to do binary searches against arrays of arbitrary object types. So I'd like to do something like this:
type Comparator = <Type>(a: Type, b: Type) => -1 | 0 | 1;
static bsearch<Type extends { compare?: Comparator }>(
ary: Type[],
value: Type
): number { ... }
My goal is to specify that Type must extend a type that may or may not include the compare method. In my function, I will check whether the compare method exists on the value parameter and call if it does, or use a generic function (that uses < and ===) if it does not.
The definition of bsearch() does not produce any warnings or errors, but attempts to invoke it from my unit test does:
class Person {
name: string;
length: number;
compare: Comparator<Person>; // What goes here?
}
describe('Utils tests', () => {
const arrayOfInt = [10, 20, 30, 40];
const arrayOfStr = ['Alfred', 'Bob', 'Chuck'];
const arrayOfPersons: Person = [
{name:'Barney',length:2},
{name:'Fred',length:6}
{name:'Wilma',length:12},
];
it('can find integer in an array of integers', () => {
let search_for = 30;
let result = Utils.bsearch(arrayOfInt, search_for)
expect(result).to.be.equal(2);
});
it('can find string in an array of strings', () => {
let search_for = 'Bob';
let result = Utils.bsearch(arrayOfStr, search_for)
expect(result).to.be.equal(1);
});
it('can find Person in an array of Persons', () => {
// This one uses Person.compare() to do the search.
// The previous two tests used the fallback technique.
let search_for = {name:'Fred',length:6};
let result = Utils.bsearch(arrayOfPersons, search_for)
expect(result).to.be.equal(1);
});
});
The error message is:
TS2345: Argument of type 'number[]' is not assignable to parameter of type '{ compare?: Comparator | undefined; }[]'.   Type 'number' has no properties in common with type '{ compare?: Comparator | undefined; }'.
I would appreciate pointers to other techniques if there is a better way to accomplish this (I'm still a TypeScript newbie).
Your generic is:
Type extends { compare?: Comparator }
Which means that Type must fulfill { compare?: Comparator } type. While passing object value, for example { name: 'Barney', length: 2, comparator: /* snip */}, is obviously correct, it's not the case for primitives like 10 and Bob. You need to include information about primitive types in the generic, for example:
Type extends ({ compare?: Comparator }) | number | string
Also, you'd probably want to enrich a bit the object typing:
{[key: string]: unknown, compare?: () => void } | number | string
Because, based on your description, you'd also want to accept also objects that do not have compare function in their type signature at all. If it does sound strange, I recommend reading about excess property checking.

map function not accepting stream of 'Subjects'

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: {}}))));

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.

Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: LIST

I tried to use ADD in UpdateExpression to add an email string into a string set , code as below , but hit this exception : Invalid UpdateExpression: Incorrect operand type for operator or function; operator: ADD, operand type: LIST.
I think the point is that I need a way to change the type into "string set" , but not sure what is the semantic to achieve that.
response = wishesTable.update_item(
Key={
'title': wishTitle,
'userMail': wishUsermail
},
UpdateExpression='ADD whoLikeList :my_value',
ExpressionAttributeValues={
":my_value": [userEmail]
},
ReturnValues="UPDATED_NEW"
)
By referring to TypeSerializer class ( http://boto3.readthedocs.io/en/latest/_modules/boto3/dynamodb/types.html
)
Changing the code to below , it would be treat as set :
response = wishesTable.update_item(
Key={
'title': wishTitle,
'userMail': wishUsermail
},
UpdateExpression='ADD whoLikeList :my_value',
ExpressionAttributeValues={
":my_value": set([userEmail])
},
ReturnValues="UPDATED_NEW"
)

Resources