Selectors No overload matches this call - ngrx

Here's my selector.ts
export interface ITestState {
value: number;
}
export interface IReduxState {
test: ITestState;
}
export const selectTest = (state: IReduxState) => state.test;
export const selectTestValue = createSelector(
selectTest,
(state: ITestState) => state.value
);
Ïf i try to use it in app.component.ts
Like so
constructor(private store: Store) {
this.vaschal$ = store.select(selectTestValue);
}
I get the following error
No overload matches this call.
Overload 1 of 9, '(mapFn: (state: object) => number): Observable<number>', gave the following error.
Argument of type 'MemoizedSelector<IReduxState, number, DefaultProjectorFn<number>>' is not assignable to parameter of type '(state: object) => number'.
Types of parameters 'state' and 'state' are incompatible.
Property 'test' is missing in type '{}' but required in type 'IReduxState'.
Overload 2 of 9, '(key: never): Observable<never>', gave the following error.
Argument of type 'MemoizedSelector<IReduxState, number, DefaultProjectorFn<number>>' is not assignable to parameter of type 'never'
angular version 11.2.4
What do i do wrong?

You need to inform the Store of the root store state:
constructor(private store: Store<IReduxState>) {
this.vaschal$ = store.select(selectTestValue);
}

Related

Has anyone received this error when inserting a calendar event using the Google Calendar API? Related to BodyResponseCallback<Schema$Event> ts(2769)

I am coding in Typescript and trying to insert an event but I am getting this error that the body of what I am inserting "is not assignable to parameter of type 'BodyResponseCallback<Schema$Event>'." I have tried a few different things and even also seen tutorials do it this way but I don't think the error should be acceptable unless if it really is some bug in the source code? Does anyone see what may be the issue here? Thanks in advance. Please see the code and error message below.
router.post('/create-event', (req: CustomRequest, res, next) => {
try {
void (async () => {
const { description, startDateTime, endDateTime } = req.body
oAuth2Client.setCredentials({
refresh_token:
(hidden)
})
const calendar = google.calendar('v3')
const response = await calendar.events.insert({
auth: oAuth2Client,
calendarId: 'primary',
requestBody: {
description: description,
colorId: '7',
start: {
dateTime: new Date(startDateTime),
},
end: {
dateTime: new Date(endDateTime),
},
// see req.body available properties that could help with timeagent
},
})
res.send(response)
})()
} catch (error) {
console.log(error)
next(error)
}
})
The "auth: oAuth2Client," is underlined in red and says:
(alias) const oAuth2Client: OAuth2Client
import oAuth2Client
No overload matches this call.
Overload 2 of 6, '(callback: BodyResponseCallback<Schema$Event>): void', gave the following error.
Argument of type '{ auth: OAuth2Client; calendarId: string; requestBody: { description: string; colorId: string; start: { dateTime: Date; }; end: { dateTime: Date; }; }; }' is not assignable to parameter of type 'BodyResponseCallback<Schema$Event>'.
Object literal may only specify known properties, and 'auth' does not exist in type 'BodyResponseCallback<Schema$Event>'.ts(2769)
I solved this by adding { responseType: 'json' } as the second argument to the insert function. It seems like an issue with types in the SDK.

Flow property is missing in mixed passed - despite the type annotation

I have the following in my declarations file (included in my [libs]):
export type EtlFieldNoIdxT = {
name: Name,
purpose: Purpose,
}
export type EtlFieldT = {
idx: number,
...EtlFieldNoIdxT
}
And the following in my use of the types:
export const createEtlField = (
etlFields: { [Name]: EtlFieldT },
newField: EtlFieldNoIdxT,
) => {
if (etlFields === {}) {
throw new Error({
message: 'Cannot create a new etlField with an empty etlFields',
});
}
const field: EtlFieldT = {
idx: maxId(etlFields, 'idx') + 1,
...newField,
};
const subject: Name = Object.values(etlFields).find(
(f) => f.purpose === 'subject', // <<< f.purpose "missing in mixed" error
).name; // <<< .name "missing in mixed" error
return newEtlField(field, subject);
};
Despite having annotated the input, can flow not infer the type of what Object.values would thus return?
Thank you in advance for pointing out my misunderstanding.
- E
If you check the declaration for Object.values you'll find that it returns an array of mixed:
static values(object: $NotNullOrVoid): Array<mixed>;
A quick google search came back with
https://davidwalsh.name/flow-object-values
So to solve your issue, you wrap Object.values(...) with any, and then inside your find arg you can type it as EtlFieldT and finally refine your type back to EtlFieldT after find.
const subject: Name = ((Object.values(etlFields): any).find(
(f: EtlFieldT) => f.purpose === 'subject',
): EtlFieldT).name;
Though you should be aware that find has the possibility of returning undefined. So to be sound, you should run the find, and declare subject if the value exists.

Conditonally returning Observable<Action> within Ngrx Effect

I'm currently refactoring my code to include the ngrx store. To minimise the amount of API calls of my LoadDeals() action, I'm checking in an effect if the store is empty. Only if it is empty, go on and make an API call. I first tried to use this pattern found here on SO (https://stackoverflow.com/a/50527652/2879771).
I realised the downside is, that every LoadDeals() call is ignored if there is data in the store. To have the possibility of forcing a load, I included an optional boolean payload to the LoadDeals() class. If this is set to true, do call the API.
Here's my first try
#Effect() loadDeals$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
switchMap(([action, hasLoaded]) => {
if (!hasLoaded || action.force) {
return this._deals.deals.pipe(
map(deals => new LoadDealsSuccess(deals)),
catchError(error => of(new LoadDealsFail(error)))
);
} else {
return of(new LoadDealsSkip());
}
})
);
But this yields the following error:
Argument of type '([action, hasLoaded]: [LoadDeals, boolean]) => Observable<LoadDealsSuccess | LoadDealsFail> | Observable<LoadDealsSkip>' is not assignable to parameter of type '(value: [LoadDeals, boolean], index: number) => ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSuccess | LoadDealsFail> | Observable<LoadDealsSkip>' is not assignable to type 'ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSkip>' is not assignable to type 'ObservableInput<LoadDealsSuccess | LoadDealsFail>'.
Type 'Observable<LoadDealsSkip>' is not assignable to type 'Iterable<LoadDealsSuccess | LoadDealsFail>'.
Property '[Symbol.iterator]' is missing in type 'Observable<LoadDealsSkip>'.
Here is my deals.actions.ts
import { Action } from '#ngrx/store';
import { ITmsCpRecord } from '#models/cp';
export enum DealsActionTypes {
LOAD_DEALS = '[Deals] Load Deals',
LOAD_DEALS_FAIL = '[Deals API] Load Deals Fail',
LOAD_DEALS_SUCCESS = '[Deals API] Load Deals Success',
LOAD_DEALS_SKIP = '[Deals Store] Load Deals Skip (cached)'
}
export class LoadDeals implements Action {
readonly type = DealsActionTypes.LOAD_DEALS;
constructor(public force: boolean = false) {}
}
export class LoadDealsFail implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_FAIL;
constructor(public payload: any) {}
}
export class LoadDealsSuccess implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_SUCCESS;
constructor(public payload: ITmsCpRecord[]) {}
}
export class LoadDealsSkip implements Action {
readonly type = DealsActionTypes.LOAD_DEALS_SKIP;
}
// action types
export type DealsAction = LoadDeals|LoadDealsFail|LoadDealsSuccess|LoadDealsSkip;
So I split it into separate effects listening to the same action but with a different filter operator. This works fine. Although I would like to not split it because it is some redundant code.
Does someone see my error? Cheers
#Effect() loadDeals$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
filter(([action, hasLoaded]) => !hasLoaded || action.force),
switchMap(() => {
return this._deals.deals.pipe(
map(deals => new LoadDealsSuccess(deals)),
catchError(error => of(new LoadDealsFail(error)))
);
})
);
#Effect() loadDealsSkip$: Observable<Action> = this._actions$.pipe(
ofType<LoadDeals>(actions.LOAD_DEALS),
withLatestFrom(this._store.pipe(select(getDealsLoaded))),
filter(([action, hasLoaded]) => hasLoaded && !action.force),
switchMap(() => of(new LoadDealsSkip()))
);
You will probably not like this answer, but I would suggest to create 2 actions for this.
One load action like you already have, and another force load action.
This would also mean creating 2 effects, but in the second one you won't have to select from store.

Can't subscribe to results of combineLatest

My app broke when I updated to RxJS 6. I got most of it working but this one method has me stumped.
Previously we had an array of observables being flatMapped and then used combineLatest like this:
const newObservable = myArrayOfObservables
.flatMap(observables => {
return Observable.combineLatest(observables);
});
And I could subscribe to the newObservable and get an array of the latest outputs from all the others.
Now I'm trying to do something like this:
const mergedList$ = chatList$.pipe(
mergeMap(res => {
return combineLatest(res);
}));
This gives me one of those really long and convoluted
Argument of type '(res: Observable<{ $key: string; }>[]) => OperatorFunction<{}, [{}, Observable<{ $key: string; }>]>' is not assignable to parameter of type '(value: Observable<{ $key: string; }>[], index: number) => ObservableInput<{}>'.
Type 'OperatorFunction<{}, [{}, Observable<{ $key: string; }>]>' is not assignable to type 'ObservableInput<{}>'.
Type 'OperatorFunction<{}, [{}, Observable<{ $key: string; }>]>' is not assignable to type 'Iterable<{}>'.
Property '[Symbol.iterator]' is missing in type 'OperatorFunction<{}, [{}, Observable<{ $key: string; }>]>'.
which quite frankly my dyslexia prevents me from parsing.
If I just return res in the above, and then try
const mergeCombo = combineLatest(mergedList$);
now mergeCombo is not an observable. Instead it's a
OperatorFunction<{}, [{}, Observable<{
$key: string;
}>]>
It could be worth noting that my original observables are being emitted by AngularFireObject.snapshotChanges()
You don't show how you imported combineLatest. It sort of looks like you are importing it as an operator, which has been deprecated.
Make sure you import it like so:
import {combineLatest} from "rxjs";
Then your original code should work just fine:
const mergedList$ = chatList$.pipe(
mergeMap(res => combineLatest(res))
);

How do I statically type a response from `window.fetch` with Flow?

I'm window.fetch'ing a response from an JSON API, and I'd like to type check my access to the response. For example:
type Result = {|+text: string, +metadata: {...}|};
type ApiResponse = Response & {|
json: () => Result,
text: null,
|};
const getResult = (): Promise<ApiResponse> => fetch(url);
// access to getResult().then(r => r.json()) is type checked against Result
But Flow fails to type check with:
Error: src/data/fetcher.js:18
v-
18: export type ApiResponse = Response & {|
19: json: () => Promise<Result>,
20:
...:
23: |};
-^ exact type: object type. Inexact type is incompatible with exact type
987: declare function fetch(input: RequestInfo, init?: RequestOptions): Promise<Response>;
^^^^^^^^ Response. See lib: /private/tmp/flow/flowlib_211b7075/bom.js:987
Which I guess makes sense because it can't reconcile fetch's return type of Promise<Response> with getResult's return type of Promise<ApiResponse>.
How can I constrain that the thing getResult is returning is a Promise?
How can I constrain that the thing getResult is returning is a Promise?
Type it as a Promise<Response>
The type for Response.json() already resolves to any, so you can assert it is whatever type you want:
declare class Response {
...
json(): Promise<any>;
...
}
The next question you might have is "How do I let Flow know the type returned upon calling json()?"
Type that as whatever you're expecting. Something like this:
fetch(url)
.then(res => res.json())
.then((obj: Result) => {
// Access your obj here
// (Preferably with some level of checking to make sure
// the API returned a valid object)
})

Resources