Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

createSelector type error with selectIds from .adapter.getSelectors() #525

Closed
herkulano opened this issue Oct 24, 2017 · 4 comments
Closed

Comments

@herkulano
Copy link
Contributor

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Feature request
[ ] Documentation issue or request

What is the current behavior?

Adding a selector with selectIds from .adapter.getSelectors() throws a type error.

Using the example-app:

export const {
  selectIds: getBookIds,
  selectEntities: getBookEntities,
  selectAll: getAllBooks,
  selectTotal: getTotalBooks
} = fromBooks.adapter.getSelectors(getBookEntitiesState)

const selectTest = createSelector(
  getBookIds,
  getBookEntities,
  (ids, entities) => {
    return { ids, entities }
  }
)

Error:

/platform-master/example-app/app/books/reducers/index.ts (97,3): Argument of type '((state: object) => number[]) | ((state: object) => string[])' is not assignable to parameter of type 'Selector<object, number[]>'.
  Type '(state: object) => string[]' is not assignable to type 'Selector<object, number[]>'.
    Type 'string[]' is not assignable to type 'number[]'.
      Type 'string' is not assignable to type 'number'.

Version of affected browser(s),operating system(s), npm, node and ngrx:

@ngrx/entity 4.1.0

@brandonroberts
Copy link
Member

Did you change the interface type for the Book to number?

@herkulano
Copy link
Contributor Author

@brandonroberts no, the example-app is untouched except for the above code.

@herkulano
Copy link
Contributor Author

herkulano commented Oct 28, 2017

@brandonroberts

export type EntitySelectorsBase<T, V> = {
selectEntities: (state: V) => Dictionary<T>;
selectAll: (state: V) => T[];
selectTotal: (state: V) => number;
};
export interface EntitySelectorsStr<T, V> extends EntitySelectorsBase<T, V> {
selectIds: (state: V) => string[];
}
export interface EntitySelectorsNum<T, V> extends EntitySelectorsBase<T, V> {
selectIds: (state: V) => number[];
}
export type EntitySelectors<T, V> =
| EntitySelectorsNum<T, V>
| EntitySelectorsStr<T, V>;

Changing the code above with this code resolves the issue:

export type EntitySelectors<T, V> = {
  selectEntities: (state: V) => Dictionary<T>;
  selectAll: (state: V) => T[];
  selectTotal: (state: V) => number;
  selectIds: (state: V) => string[] | number[];
};

@goelinsights
Copy link

For anyone else who gets a type error: "Cannot invoke an expression whose type lacks a call signature", the union in the selectIds type that was changed in #533 is I believe the issue.

export interface EntityState<T> { ids: string[] | number[]; ... }
I got this trying to check if the id exists in a guard.
return this._store.pipe( select(getProductIds), map(productIds => productIds.filter(productId => productId === id)),

Current workaround is to escape the type for getProductIds:
select(<any>getProductIds)

@brandonroberts do you have a better suggestion for getting access to Array commands without triggering the type error?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants