Flow: how to extend native JS object (especially Promise)? - flowtype

// #flow
type Deferred = Promise<any> & {
reject: Function;
resolve: Function;
};
/** Deferred based on Promise
#return {Promise} */
export default (): Deferred => {
let res, rej;
let deferred: Deferred = Object.assign(
new Promise( ( resolve, reject ) => {
res = resolve;
rej = reject;
}),
{ 'resolve': res, 'reject': rej }
);
return deferred;
};
Right now this code gives such errors:
Cannot assign Object.assign(...) to deferred because:
property reject is missing in Promise [1] but exists in object type [2].
property resolve is missing in Promise [1] but exists in object type [2].
Property reject is missing in Promise [1].
Property resolve is missing in Promise [1].
And the question is: how to correctly document this code without errors?

It's not a good idea to use any.
It's not a good idea to use Function because it's just an alias for any.
It's better not to use &: it's broken. Use type spread instead.
If you really want to extend Promise, just extend it like this https://flow.org/try/#0PTAEAEDMBsHsHcBQBjaBDAzh0ARAppHgE5F4AmAPACoB8oeAHgC54B2Z2ACkbALYCWGPNToBvRKFABiUhljQAbngBcoABRUAlKAC8dfIRLkRoAD6gFsfmQDcE6aQBWeZE1VqBDctr24CxUkpaMwsrW3t7ZFhWDCYiAFdXWCI1SFYAfndZeSVM9S1dOk9yABpQJxcmPI9+LzIfItrvQtDrbXFJSSiYplAABx4GAE9dUFEAXztO0Ax4vuI1NWzFPDKK1wax+2mB2GGAOmWlUaO8Ken+waHDvGdXE9vK8+n+SHU07TSlvDkVtceNs9QONNECmAALQT7GQ-HJ4Ua7A6nMGQjDQ9a9HSXPbXDHncYRSSnb6zaBuUBaVQGALGYIdToQqEw35KEnxMmg7blPBMeJEVigRkYfGIewYtQBZKqYr1Kn+IxBMRcoXogFMCUkZKc6akXn8wWokWSRCTUXdWKgMgEUasPDwPyGQJqTmIECgeDJADWGEQVsgNxZeDUAEZNPsIWxFgxVKx4rwAEbETbm+R4fZwADmagYmk5bqiRlc0BGGHBCGwaAFkqIvoIAbhIbDEdYUdUsSI-FYGeT0V+acz2dzdkQjD6yV6frQ7N61IVdiAA
class Deferred<T> extends Promise<T> {
#resolve: (T) => Deferred<T> | void;
#reject: (mixed) => Deferred<T> | void;
constructor(fn?: (resolve?: (T) => mixed, reject?: (mixed) => mixed) => void) {
const proxy = {};
super((resolve, reject) => {
proxy.resolve = resolve;
proxy.reject = reject;
if (fn) fn(resolve, reject);
});
this.#resolve = proxy.resolve;
this.#reject = proxy.reject;
}
resolve(result: T): Deferred<T> {
this.#resolve(result);
return this;
}
reject(error: mixed): Deferred<T> {
this.#reject(error);
return this;
}
};

Related

Confused with this async thunk

export const loginSuccess = createAsyncThunk(
"auth/loginSuccess",
async (user: User) => {
const res = await api
.post(
"/auth/loginSuccess",
{ user },
{
withCredentials: true,
}
)
.then((res: any) => {
setAxiosToken(res.data.token);
saveToken(res.data.token);
return { ...res.data.data, token: res.data.token };
});
return res;
}
);
There are 2 return statements at the end so I am confused about which return value the fulfilled reducer will get. The code is written by someone else that's why I want to understand it.
The second return statement is the one which will return from your function.
The first is actually returning from the then function of the promise that axios returns.
This is made a little bit confusing by using the same name for the res variable in the thunk function, and for the response variable that is passed on the the then function.
But what you will receive back is the object generated in this line of code:
{ ...res.data.data, token: res.data.token }
Where res.data.data is spread into a new object, and res.data.token is assigned to the token property of that object.

How to test asynchonous functions using sinon?

I have a class called PostController, and I trying to test the following function create:
class PostController {
constructor(Post) {
this.Post = Post;
}
async create(req, res) {
try {
this.validFieldRequireds(req);
const post = new this.Post(req.body);
post.user = req.user;
...some validations here
await post.save();
return res.status(201).send(message.success.default);
} catch (err) {
console.error(err.message);
const msg = err.name === 'AppError' ? err.message :
message.error.default;
return res.status(422).send(msg);
}
}
My test class is:
import sinon from 'sinon';
import PostController from '../../../src/controllers/posts';
import Post from '../../../src/models/post';
describe('Controller: Post', async () => {
it.only('should call send with sucess message', () => {
const request = {
user: '56cb91bdc3464f14678934ca',
body: {
type: 'Venda',
tradeFiatMinValue: '1',
... some more attributes here
},
};
const response = {
send: sinon.spy(),
status: sinon.stub(),
};
response.status.withArgs(201).returns(response);
sinon.stub(Post.prototype, 'save');
const postController = new PostController(Post);
return postController.create(request, response).then(() => {
sinon.assert.calledWith(response.send);
});
});
});
But I'm getting the following error:
Error: Timeout of 5000ms exceeded. For async tests and hooks, ensure
"done()"
is called; if returning a Promise, ensure it resolves.
(D:\projeto\mestrado\localbonnum-back-end\test\unit\controllers\post_spec.js)
Why?
Most probably it's because misuse of sinon.stub.
You've
sinon.stub(Post.prototype, 'save');
without telling what this stub will do, so in principle this stub will do nothing (meaning it returns undefined).
IDK, why you don't see other like attempt to await on stub.
Nevertheless, you should properly configuture 'save' stub - for example like this:
const saveStub = sinon.stub(Post.prototype, 'save');
saveStub.resolves({foo: "bar"});

Return Observable after subscription

const orgsArr = [];
organizations.map(orgid => {
this.afs.collection('users').doc<Organization>(orgid).valueChanges()
.map(x => {
orgsArr.push(x);
}).subscribe();
});
return Observable.of(orgsArr);
orgsArr resturns before subscribe()
You're mixing asynchronous code with synchronous code. Your method calls orgsArr.push from within an observable .map call, which won't have executed by the time you return Observable.of(orgsArr)
You're also mis-using map on organizations.map, as map is meant to return something and constructs an array.
You can re-factor this to use a concat with all the Observable returned from the orgs mapped valueChanges() and then a reduce to convert a stream of values into a single array:
const orgValueObsArray = organizations.map(orgid => {
return this.afs.collection('users').doc<Organization>(orgid).valueChanges();
});
return Observable.concat(...orgValueObsArray)
.reduce((acc, val) => {
acc.push(val);
return acc;
}, []);

The implementation of Redux's applyMiddleware

My question is why middlewareAPI can't use :
const middlewareAPI = {
getState: store.getState,
dispatch: dispatch
}
to replace the definition in the source code as below:
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args) // why not just use `dispatch: dispatch`
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
Anyone can tell me the difference ? Thanks.
It's a somewhat complicated combination of JS variable scoping/hosting, and needing to ensure that the passed-in dispatch method actually points back to the start of the middleware chain.
Please see the newly-added (and not yet published) Redux FAQ entry on why applyMiddleware uses a closure for more details.

RxJS and AngularJS HTTP - how can I achieve this?

I'm writing a small utility function that wrap a call to AngularJS http.get with the necessary authentication headers:
get(endpoint: string): Observable {
var headers = new Headers();
this._appendAuthentificationHeaders( headers, this.user.credentials);
return this.http.get(endpoint, { headers: headers })
.map(res => res.json());
}
The point here is that if this.user is null, the method will just crash.
So I have three options:
Return null and check that return value on every call...
Throw an exception
Find a way to also return an RxJS Observable object that will directly trigger the error handler.
I would like to implement the third method, as it would allow me unify this method's behavior: It always returns an observable no matter what happen.
Do you have an idea about how to do that?
Do I have to create a new Observable and kind of merge those two?
What can I do?
If the user is null, you can simply return a raw observable that triggers an error:
if (this.user == null) {
return Observable.create((observer) => {
observer.error('User is null');
});
}
(...)
or leverage the throw operator:
if (this.user == null) {
return Observable.throw('User is null');
}
(...)
This way the second method of the subscribe method will be called:
observable.subscribe(
(data) => {
(...)
},
(err) => {
// Will be called in this case
}
);
I think the cleanest way would be to wrap the whole function body to an observable, as it will turn any accidental error to an observable error. Something like this:
get(endpoint: string): Observable {
return Rx.Observable.defer(() => {
var headers = new Headers();
this._appendAuthentificationHeaders(headers, this.user.credentials);
return Rx.Observable.just(headers);
})
.flatMap(headers => this.http.get(endpoint, { headers: headers }))
.map(res => res.json());
}
However I still do not agree with http.get returning an observable instead of a promise. As these are single valued observables, your function could be a simple async function (sry, js instead of ts):
async get(endpoint) {
var headers = new Headers();
this._appendAuthentificationHeaders(headers, this.user.credentials);
const res = await this.http.get(endpoint, { headers })).toPromise();
return res.json();
}

Resources