Argument of type '(snap: DataSnapshot) => void' is not assignable to parameter of type '(a: DataSnapshot) => boolean' - ionic-framework

I've already read several questions and answers about this problem but wasn't able to solve it.
I'm using Ionic2 and I have a method which retrieves data from Firebase Database v3.
I don't understand why I get following error in console when I do ionic serve:
Error TS2345: Argument of type '(snap: DataSnapshot) => void' is not assignable to parameter of type '(a: DataSnapshot) => boolean'.
Type 'void' is not assignable to type 'boolean'.
This is the method:
constructor(private http: Http) {
firebase.database().ref('users').orderByChild("id").on("value", function(snapshot){
let items = [];
snapshot.forEach(snap => {
items.push({
uid: snap.val().uid,
username: snap.val().username,
});
});
});
}
}

The forEach method in the DataSnapshot has this signature:
forEach(action: (a: firebase.database.DataSnapshot) => boolean): boolean;
as the action can return true to short-circuit the enumeration and return early. If a falsy value is returned, enumeration continues normally. (This is mentioned in the documentation.)
To appease the TypeScript compiler, the simplest solution would be to return false (to continue enumerating the child snapshots):
database()
.ref("users")
.orderByChild("id")
.on("value", (snapshot) => {
let items = [];
snapshot.forEach((snap) => {
items.push({
uid: snap.val().uid,
username: snap.val().username
});
return false;
});
});

For Typescript version I came out with this solution:
db
.ref(`jobs`)
.orderByChild("counter")
.on("value", (querySnapshot) => {
const jobs: any[] = [];
querySnapshot.forEach((jobRef) => {
jobs.push(jobRef.val());
});
jobs.forEach(async (job) => {
await minuteRT(job);
});
res.status(200).send("done!");
});

In my case I had to return true, to cancel the enumeration:
// You can cancel the enumeration at any point by having your callback
// function return true. For example, the following code sample will only
// fire the callback function one time:
var query = firebase.database().ref("users").orderByKey();
query.once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key; // "ada"
// Cancel enumeration
return true;
});
});
Documentation: [https://firebase.google.com/docs/reference/js/v8/firebase.database.DataSnapshot#foreach][1]

Related

The argument type 'String' can't be assigned to the parameter type 'int' how can i fix it?

im new to flutter and ive got some issue with my code
how can i fix this problem ?
im stucked with this problem for few days and still cannot fix it
The argument type 'String' can't be assigned to the parameter type 'int'
Here's my error part
Services.updateEmployee(
employee.id, _firstNameController.text, _lastNameController.text)
.then((result) {
if ('success' == result) {
_getEmployees(); // Refresh the list after update
setState(() {
_isUpdating = false;
});
Here's the method
_updateEmployee(Employee employee) {
setState(() {
_isUpdating = true;
});
_showProgress('Updating Employee...');
Services.updateEmployee(
employee.id, _firstNameController.text, _lastNameController.text)
.then((result) {
if ('success' == result) {
_getEmployees(); // Refresh the list after update
setState(() {
_isUpdating = false;
});
_clearValues();
}
});
Your method is looking for an int but you are passing a String, that's why it's giving you an error.
Example:
// Doesn't give you an error
testMethod(1);
// Gives you an error (The argument type 'String' can't be assigned to the parameter type 'int')
testMethod("1");
void testMethod(int empId) {
print(empId);
}
Hope this helped to fix your error.

How to access Marshalling iOS [Nativescript]

I currently have a functional plugin, but I have a problem being able to get the object in the finishCheckout method
import { Options } from "./mercadopago-px.common";
import * as frameModule from "tns-core-modules/ui/frame";
export class LifeCycleProtocolImpl extends NSObject
implements PXLifeCycleProtocol {
public resolve: any;
public reject: any;
static ObjCProtocols = [PXLifeCycleProtocol]; // define our native protocalls
static new(): LifeCycleProtocolImpl {
return <LifeCycleProtocolImpl>super.new(); // calls new() on the NSObject
}
cancelCheckout(): () => void {
this.reject({
status: "cancel",
data: null,
error: "cancelCheckout"
});
return null;
}
changePaymentMethodTapped?(): () => void {
return null;
}
finishCheckout(): (result: PXResult) => void {
this.resolve({
status: "finishCheckout",
data: null,
error: null
});
return null;
}
}
export class MercadopagoPx {
public start(options: Options): Promise<any> {
return new Promise((resolve, reject) => {
let checkout = MercadoPagoCheckout.alloc().initWithBuilder(
MercadoPagoCheckoutBuilder.alloc()
.initWithPublicKeyPreferenceId(
options.publicKey,
options.preferenceId
)
.setLanguage(options.language)
);
let lifeCycleProtocolDelegate: LifeCycleProtocolImpl = LifeCycleProtocolImpl.new();
lifeCycleProtocolDelegate.resolve = resolve;
lifeCycleProtocolDelegate.reject = reject;
let pxLifeCycleProtocol: PXLifeCycleProtocol = lifeCycleProtocolDelegate;
checkout.startWithNavigationControllerLifeCycleProtocol(
frameModule.topmost().ios.controller,
pxLifeCycleProtocol
);
});
}
}
My custion is how to access here, actually not access because i have wrong with linter TS :
finishCheckout(): (result: PXResult) => void {
console.dir(result); <---- Here error, can't access to result
this.resolve({
status: "finishCheckout",
data: null,
error: null
});
return null;
}
Trying to access the object, I can not because it detects that the variable does not exist, when it is present, I do not know if it is the way to access the property, or if there is a way to access that object that returns the method to me which try to implement
It means you are returning a function from finishCheckout which has a parameter result.
finishCheckout(): (result: PXResult) => void {
console.dir(result); <---- Here error, can't access to result
this.resolve({
status: "finishCheckout",
data: null,
error: null
});
return null;
}
It suppose to be,
finishCheckout(result: PXResult) {
console.dir(result);
this.resolve({
status: "finishCheckout",
data: null,
error: null
});
return null;
}
if result should be a parameter for finishCheckout.
Edit:
As per the typings (finishCheckout(): (p1: PXResult) => void;), the method doesn't have a parameter but it returns a function that will have result as a parameter. Hence you can't access result in there.

Flow(InferError): Cannot call await with 'axios.get(...)' bound to 'p'

I'm getting some Flow errors using axios.
Cannot call await with 'axios.get(...)' bound to 'p' because:
Either property 'error_message' is missing in 'AxiosXHR'.
Or property 'data' is missing in 'Promise'
Here is my code, with an attempted type annotation. (Same error without the AxiosPromise<Object> annotation.) The error is on axios.get(url).
async handleAddressChange(): AxiosPromise<Object> {
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleMapsApiKey}&input=${this.state.address}`;
try {
const { data, error_message } = await axios.get(url);
if (error_message) throw Error(error_message);
this.setState({
addressPredictions: data.predictions,
showPredictions: true
});
} catch (err) {
console.warn(err);
}
}
Funny thing is that in another file axios gives no Flow problems:
export async function loginWithApi(creds: AuthParams) {
const res = await axios.get(ApiUrls.login, { params: creds });
return res.data;
}
I have import type { AxiosPromise, $AxiosXHR } from "axios"; in my file.
Anyone know how to fix this?
In case of error there will be no error_message in returned payload, but the error goes into the catch block.
Also, the handleAddressChange does not returns AxiosPromise, instead it returns implicit promise, as it defined with async
So, something like this:
async handleAddressChange(): Promise<void> {
const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?key=${GoogleMapsApiKey}&input=${this.state.address}`;
try {
const { data } = await axios.get(url);
this.setState({
addressPredictions: data.predictions,
showPredictions: true
});
} catch (err: AxiosError) {
new Error(err);
}
}
Might work for you. Note the AxiosError definition.
One extra note is that you can add returned payload into the AxiosPromise generic, i.e.:
type TExpectedLoginResponse = {
ok: boolean,
token: string
}
export async function loginWithApi(creds: AuthParams): AxiosPromise<TExpectedLoginResponse> {
const res = await axios.get(ApiUrls.login, { params: creds });
return res.data; // so now flow knows that res.data is type of TExpectedLoginResponse
}
Hope it helps.

Custom Validator Angular 2

I've written a web api function that takes a username from the textfield and checks if the username is already taken. To know if the username is available or not, my server returns Y if it is available and N if its not.
To validate the username, I'm using a ValidatorFn in Angular2 so validate the input. However, my validator function is not working.
Here is the validator function:
interface Validator<T extends FormControl> {
(c: T): { [error: string]: any };
}
function validateUsername(c: string) : ValidatorFn {
return (this.isAvailable(c)=='Y') ? null : {
validateUsername: {
valid: false
}
};
}
Here is the isAvailable function:
private isAvailable(username: string) {
let usernameAvailable;
let url = 'URL/api/auth/checkuser/' + username;
let headers = new Headers();
headers.append('User', sessionStorage.getItem('username'));
headers.append('Token', sessionStorage.getItem('token'));
headers.append('AccessTime', sessionStorage.getItem('AccessTime'));
let options = new RequestOptions({ headers: headers });
this.http.get(url, options)
.subscribe((res: Response) => usernameAvailable);
return usernameAvailable; //returns Y or N
}
Form Builder:
complexForm: FormGroup;
constructor(private http: Http, fb: FormBuilder) {
this.complexForm = fb.group({
'username': [null, Validators.compose([Validators.required, Validators.minLength(5), Validators.maxLength(10), validateUsername(this.complexForm.controls['username'].value)])],
})
}
validateUsername(this.complexForm.controls['username'].value) is failing and I'm getting this error:
[ts] Type '{ validateUsername: { valid: boolean; }; }' is not assignable to type 'ValidatorFn'. Object literal may only specify known properties, and 'validateUsername' does not exist in type 'ValidatorFn'. (property) validateUsername: {
valid: boolean;
}
You not adding your validator function correctly. You don't need to call your function when you register it:
this.complexForm = fb.group({
'username': [null, Validators.compose(
[
Validators.required,
Validators.minLength(5),
Validators.maxLength(10),
validateUsername <----- don't call it here
]
)],
})
You can see that some functions are called:
Validators.minLength(5),
But that is factory function call and not a validator function call. During initialization they return ValidatorFn:
/**
* Validator that requires controls to have a value of a minimum length.
*/
static minLength(minLength: number): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
...
}
See more in the official docs.
Also, it seems that your validator is async, so you have to pass it in the async array. And I don't think you need Validators.compose. The correct configuration should therefore be like this:
this.complexForm = fb.group({
'username': [null, [
Validators.required,
Validators.minLength(5),
Validators.maxLength(10),
], [validateUsername]]
})
Regarding the error:
Type '{ valid: boolean; }' is not assignable to type ValidatorFn.
You need to use the correct return type ValidationErrors instead of ValidatorFn:
function validateUsername(c: string) : ValidationErrors {
return (this.isAvailable(c)=='Y') ? null : {
validateUsername: {
valid: false
}
};
}

Is it possible to create dynamic getters/setters in typescript?

I'm new in typescript, and I'm trying to rewrite our application from es2016 to TypeScript.
My task is to have a class with data property and make each element from data object available as class property.
I get stuck on this JavaScript code:
for(let key in this.data) {
Object.defineProperty(this, key, {
get: function(value:any) { return this.data[key]; },
set: function(value:any) {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
It is pretty easy to use getter/setters for typescript, but i get confused if i can create them dynamically?
interface IData {
id: number;
[propName: string]: any;
}
class Model {
protected updatedKeys:string[] = [];
baseUrl:string = null;
data:IData;
fields:IData;
constructor(data:IData={id:null}, fields:IData={id:null}) {
super();
this.data = data;
this.fields = fields;
for(let key in this.data) {
Object.defineProperty(this, key, {
get: function(value:any) { return this.data[key]; },
set: function(value:any) {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
}
}
tsc -t ES2016 --lib "es2016","dom" models.ts
will give this error:
models.ts(33,40): error TS2345: Argument of type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to parameter of type 'PropertyDescriptor & ThisType<any>'.
Type '{ get: (value: any) => any; set: (value: any) => void; }' is not assignable to type 'PropertyDescriptor'.
Types of property 'get' are incompatible.
Type '(value: any) => any' is not assignable to type '() => any'.
And I don't know how to get rid of this problem.
thanks to the https://github.com/epicgirl1998, she helped me to find the solution. I'll post it here:
the error is that the getter has a value parameter even though getters
aren't passed any value
i replaced it with get: function() { return this.data[key]; }, and now
the only error is that there's a super call in the class which is only
needed if the class extends another class
also, this inside the accessors doesn't refer to the class instance,
but using arrow functions for them should fix it
try this:
interface IData {
id: number;
[propName: string]: any;
}
class Model {
protected updatedKeys:string[] = [];
baseUrl:string = null;
data:IData;
fields:IData;
constructor(data:IData={id:null}, fields:IData={id:null}) {
this.data = data;
this.fields = fields;
for(let key in this.data) {
Object.defineProperty(this, key, {
get: () => { return this.data[key]; },
set: (value:any) => {
if (this.data[key] !== value) {
this.data[key] = value;
this.updatedKeys.push(key);
}
},
});
}
}
}
In typescript, you generally don't need to create objects with methods and properties dynamically. You either create instances of classes, or you type your data using an interface.
If all you want is to convert loaded (json) data to typed data, you can use an interface that describes the structure of your json data.
interface describes the properties of actor data
interface Actor {
name: string;
height: number;
}
fetch generic json data from somewhere
let data : any = getSingleActorData();
type the actor to an interface and put it in an actor array
let actorData : Actor[] = [];
actorData.push(data as Actor);
Now your IDE will allow you to access the name and height of the actor variable:
console.log(actorData[0].name);
If you do want a complete 'object' with getters and setters you can create an Actor class and then instantiate it with the data you loaded:
class Actor {
private _name:string;
private _height:string;
get name {}
set name {}
get height {}
set height {}
constructor(name:string, height:number){
}
}
And then you can put your json data in an actor instance:
actorData.push(new Actor(jsondata.name, jsondata.height));