Null conditional in Motoko? - arrays

Getting the following error:
expression of type
?Product/798
cannot produce expected type
{id : Nat; name : Text; price : Nat; sku : Text}
when trying to loop over a list of ids, get the corresponding HashMap value, and add to a new array only if the get() function returns a Product.
for (id in productIds.vals()) {
var product: ?Product = products.products.get(id);
if (product != null) {
products_list := Array.append<Product>(products_list, [product]);
};
};
Am I maybe misunderstanding the best way to approach this? It seems like I shouldn't get any errors because if it's not a Product type (which is the "expected type" it references) it should just continue on, right?

The variable product is of type ?Product, but your instantiation of the Array.append function expects an array of values of plain type Product.
The comparison with null does not magically change the type of the variable. You'll need to pattern-match it with a switch to extract the actual value:
switch product {
case (?p) { products_list := Array.append<Product>(products_list, [p]) };
case null { ...do something else... };
}

Related

Typescript: Member of union type with incompatible signature when using find on array of objects

I want to check if a value exists in an array of objects.
My array looks something like this:
[
0: {
id: 'unique_obj_id',
item: {
id: 'unique_item_id',
...
},
...
},
1: {...}
]
The objects in the array can be one of many interface types (depending on my api call, here: resource strings represent these interfaces, which are defined somewhere else). But one array will always consist of the same interface types for a given data request.
I'm trying to write a reusable function to check whether given_id exists for any object in the array for obj.item.id.
So far I've managed to write the correct logic but typescript throws some exceptions that I can't seem to figure out. shopApprovalData is a collection of interfaces each following the above object structure accessible by the indices of resource.
export type ApprovalResource = 'str1' | 'str2' | 'str3' | 'str4' | 'str5';
export const checkApprovalItem = (given_id: string, resource: ApprovalResource) => {
const shopApprovalData = useShopApprovals();
if (shopApprovalData && shopApprovalData[resource]) {
const resourceApprovalData = shopApprovalData[resource];
if (resourceApprovalData.find(e => e.item.id === id)) {
return true;
}
}
return false;
}
Typescript shows me that shopApprovalData and itemApprovalData is possibly undefined and that the expression find() is not callable since signatures of members of the union type are not compatible with each other. (Apparently, some removes the error, why?)
What approach should I choose instead to check whether the given_id exists in any object of the array?
Based on your usecase, i create this code sandbox: https://codesandbox.io/s/stackoverflow-answer-ke9drk?file=/src/index.ts
explanation:
Type wont compile, so we need something to mark what the interface of the object.
Also i may confused by your code shopApprovalData[resource] what do you want to achieve here? for example, if resource is str1 shopApprovalData[resource] will always return undefined because no index str1 in Array
I hope it help,
Best Regards

TypeError : Property does not exist on type

I am using a type script for the react project. I have defined the type for all values, but prop.option?I can't get the value of the name. Please tell me the answer.
type PropTypes = {
option?: OptionType[]
}
type OptionType = {
id?: number
name?: string
price: number
quantity: number
}
function OrderItemPCForm(props: PropTypes) {
console.log('===>', props.option?.name)
return(<div>...</div>)}
Property 'name' does not exist on type 'OptionType[]'.
Your problem was you defined option as an array (not an object)
option?: OptionType[]
so that when you try to access values from
console.log('===>', props.option?.name)
It will throw an error because you try to get name from option object which is not defined
It has 2 ways to fix
The first one is you should remove an array definition on option
type PropTypes = {
option?: OptionType //removed `[]`
}
The second fix can be
console.log('===>', props.option[index].name) //index can be populated from a loop
But it also depends on your intention which type you want to achieve (an array or an object on option)

Scala, Collection.searching with user-defined implicit Ordering[]

I need to perform binary search on an array of custom case class. This should be as simple as calling the search function defined in scala.collection.Searching:
As you can see, if the collection on which I call the search method is an indexed sequence, the binary search is performed.
Now, I need to create my custom Ordering[B] parameter and I want to pass it explicitly to the search function (I don't want for it to take any implicit parameter inferred from context).
I have the following code:
// File 1
case class Person(name: String, id: Int)
object Person{
val orderingById: Ordering[Person] = Ordering.by(e => e.id)
}
// File 2 (same package)
for(i <- orderedId.indices) {
// orderedId is an array of Int
// listings is an array of Person
val listingIndex = listings.search(orderedId(i))(Person.orderingById)
...
}
I get the following error:
Type mismatch. Required: Ordering[Any], found: Ordering[Nothing]
So, I tried change the implementation in this way:
// file 1
object Person{
implicit def orderingById[A <: Person] : Ordering[A] = {
Ordering.by(e => e.id)
}
}
//file 2 as before
This time getting the following error:
Type mismatch. Required: Ordering[Any], found: Ordering[Person]
Why does it happen? At least in the second case, should it convert from Any to Person?
Follow the type specifications.
If you want to .search() on a collection of Person elements then the first search parameter should be a Person (or a super-class thereof).
val listingIndex =
listings.search(Person("",orderedId(i)))(Person.orderingById)
Or, to put it in a more complete and succinct context:
import scala.collection.Searching.SearchResult
case class Person(name: String, id: Int)
val listings: Array[Person] = ...
val orderedId: Array[Int] = ...
for(id <- orderedId) {
val listingIndex: SearchResult =
listings.search(Person("",id))(Ordering.by(_.id))
}
I'll add a bit just to elaborate about your error. First, please note that Searching.search is deprecated, with deprecation message:
Search methods are defined directly on SeqOps and do not require scala.collection.Searching any more.
search is now defined on IndexedSeqOps. Let's look at the signature:
final def search[B >: A](elem: B)(implicit ord: Ordering[B])
When you call:
listings.search(orderedId(i))(Person.orderingById)
The result of orderedId(i) is Int. Therefore, B in the signature above is Int. The definition of Int is:
final abstract class Int private extends AnyVal
A is Person, because listing is of type Array[Person]. Therefore, search, is looking for a common root for both Int and Person. This common root is Any, hence you are getting this error. One way to overcome it, is to define an implicit conversion from Int to Person:
object Person{
val orderingById: Ordering[Person] = Ordering.by(e => e.id)
implicit def apply(id: Int): Person = {
Person("not defined", id)
}
}
Then the following:
val listings = Array(Person("aa", 1), Person("bb", 2), Person("dd", 4))
val orderedId = 1.to(6).toArray
for(i <- orderedId.indices) {
// orderedId is an array of Int
// listings is an array of Person
listings.search[Person](orderedId(i))(Person.orderingById) match {
case Found(foundIndex) =>
println("foundIndex: " + foundIndex)
case InsertionPoint(insertionPoint) =>
println("insertionPoint: " + insertionPoint)
}
}
will produce:
foundIndex: 0
foundIndex: 1
insertionPoint: 2
foundIndex: 2
insertionPoint: 3
insertionPoint: 3
Code run in Scastie.

how to compare the query value from url to id using react?

i want to check if the url contains ?query_param if so then get its value and compare that value to an id.
consider the url /path/20?query_parm=2234
and i have to get the param_id and compare it with the item id.
so i do something like below,
handle_location = (path) => {
let opened_item, param_id;
param_id = new
URLSearchParams(this.props.location.search).get('query_param');
if (this.state.items) {
opened_item = this.state.items.find(item => item.id ===
param_id);
}
};
the data structure for items is below,
items = [{
id: 2244;
attributes: something;
}
{
id: 33;
attributes: nothing;
}]
But this gives the opened_item value undefined since item.id is never equal to param_id... because of type being different.
How can i fix this...or is there a better way to find the query_param from url and get its value and use it accordingly to find the item that matches with the query_param value.
Given you understand that both data types are different, you could use avoid using strict equality and leverage type coercion which would work
item.id == param_id
The most efficient way though would be to convert param_id to the appropriate type before comparing e.g.
param_id = parseInt(param_id, 10);
It means one conversion and you can keep the strict equality
You will need to either cast both of the values to the same type(either Number or String) and then perform the comparison or you could use == operator which will try to coerce the types automatically(not recommended). You can also always fall back to some default value if none of the items matched the id.
if (this.state.items) {
opened_item = this.state.items.find(item => item.id ===
param_id) || 'some default value'
}
try this:
const param_id = this.props.match.params.id

Convert/add string to a specific type

I would like to convert/add a string to a type [Talent.Otherlanguages]
Talent.Otherlanguages is an enum who contain many languages.
I would like to do this : otherlanguages?.append(Talent.Otherlanguage(rawValue: langue)!)
but when i do print(otherlanguages) the value is set to nil.
Do any of you have an idea to help me ?
In case you consider otherlanguages is nil it is my assamtion. Because if you send wrong rawValue to the enum constructor you going to receive crash.So you are not checking if otherlanguages is not nil and try to append something.
This is example:
enum Languages:String {
case uk = "english "
case ua = "ukrainian"
}
var languages = [Languages]()
print(languages) //[]
languages.append(Languages(rawValue: "ukrainian")!)
print(languages) //[Languages.ua]

Resources