Comments (29)
@frankwallis , I just added your type definition to a project with some 40+ selectors. It seems to work pretty well.
For anyone who don't like to type a lot, here's some more of the "etc" part:
declare module Reselect {
type Selector<TInput, TOutput> = (state: TInput, props?: any) => TOutput;
function createSelector<TInput, TOutput, T1>(selector1: Selector<TInput, T1>, combiner: (arg1: T1) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, combiner: (arg1: T1, arg2: T2) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, combiner: (arg1: T1, arg2: T2, arg3: T3) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5, T6>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, selector6: Selector<TInput, T6>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5, T6, T7>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, selector6: Selector<TInput, T6>, selector7: Selector<TInput, T7>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, arg7: T7) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5, T6, T7, T8>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, selector6: Selector<TInput, T6>, selector7: Selector<TInput, T7>, selector8: Selector<TInput, T8>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, arg7: T7, arg8: T8) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5, T6, T7, T8, T9>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, selector6: Selector<TInput, T6>, selector7: Selector<TInput, T7>, selector8: Selector<TInput, T8>, selector9: Selector<TInput, T9>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, arg7: T7, arg8: T8, arg9: T9) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, selector6: Selector<TInput, T6>, selector7: Selector<TInput, T7>, selector8: Selector<TInput, T8>, selector9: Selector<TInput, T9>, selector10: Selector<TInput, T10>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, arg7: T7, arg8: T8, arg9: T9, arg10: T10) => TOutput): Selector<TInput, TOutput>;
function createSelector<TInput, TOutput, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, selector4: Selector<TInput, T4>, selector5: Selector<TInput, T5>, selector6: Selector<TInput, T6>, selector7: Selector<TInput, T7>, selector8: Selector<TInput, T8>, selector9: Selector<TInput, T9>, selector10: Selector<TInput, T10>, selector11: Selector<TInput, T11>, combiner: (arg1: T1, arg2: T2, arg3: T3, arg4: T4, arg5: T5, arg6: T6, arg7: T7, arg8: T8, arg9: T9, arg10: T10, arg11: T11) => TOutput): Selector<TInput, TOutput>;
function defaultMemoize(func:Function, equalityCheck:any): any;
function createSelectorCreator(memoize:Function, ...memoizeOptions:any[]): any;
function createStructuredSelector(inputSelectors:any, selectorCreator:any): any;
}
declare module "reselect" {
export = Reselect
}
from reselect.
I need to just be sure that it does not become necessary to specify the type parameters when calling createSelector
, currently I am using it like this (simplified):
interface GlobalState {
products: { [id: number] : Product; }
clients: { [id: string] : Client; }
}
interface MyComponentProps {
clientId: string;
}
const clientRepoSelector = (state: GlobalState) => state.clients;
const clientIdSelector = (state: GlobalState, props: MyComponentProps) => props.clientId;
const mapStateToProps = createSelector(
clientRepoSelector,
clientIdSelector,
(clientRepo, clientId) => clientRepo[clientId]
);
So I specify the shape of the global state and the inputs to the functions and then get type inference in the 'combiner' function and the resulting selectors. The type inference feeds into other selectors when you start combining them.
I would be quite unhappy if I had to start specifying all the type parameters whenever I called createSelector, so I would like to check that first.
Can I also ask if you are using connect
as a decorator or as a plain function as I think that can also affect the type of the resulting component.
from reselect.
@screenpunch you do not get the typed version if you load it that way.
from reselect.
I would be very happy if someone decided to create Typescript definitions. We did make some changes for the 1.0.0 release that should make them possible (#27).
from reselect.
It would also be interesting to see Flow types as well. I'm not sure whether the state of Flow is far enough along to cover all the ES6 we use. I wonder whether it's possible to generate one from the other.
from reselect.
Need this as well, right now I'm debugging errors since 1/2 hour in my code due to incorrect manual types I added when composing selectors. If the compiler would know then it would be a ton of help (plus would reduce a lot of the manual effort needed to propagate the types). I would like to help exept that I'm pretty sure I don't know enough about the typing system to write the types definitions.
from reselect.
for myself i created just most stupid definition:
declare module Reselect {
function createSelector(...args: any[]): any;
}
declare module "reselect" {
export = Reselect;
}
from reselect.
How about:
declare module "reselect" {
type Selector<TInput, TOutput> = (arg1: TInput, arg2?: any) => TOutput;
export function createSelector<TInput, TOutput, T1>(selector1: Selector<TInput, T1>, combiner: (arg1: T1) => TOutput): Selector<TInput, TOutput>;
export function createSelector<TInput, TOutput, T1, T2>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, combiner: (arg1: T1, arg2: T2) => TOutput): Selector<TInput, TOutput>;
export function createSelector<TInput, TOutput, T1, T2, T3>(selector1: Selector<TInput, T1>, selector2: Selector<TInput, T2>, selector3: Selector<TInput, T3>, combiner: (arg1: T1, arg2: T2, arg3: T3) => TOutput): Selector<TInput, TOutput>;
/* etc */
}
from reselect.
Yes they're working pretty well for me too, and providing type-inference in the 'combiner' function which is really useful. Thanks for filling out more of the overloads, I've submitted a PR to DefinitelyTyped.
from reselect.
@frankwallis works nicely, thanks a bunch!
from reselect.
Hey, this is great, thanks everyone! I'll add a link to here from the readme.
Do you think you could let me know if they accept the PR to DefinitelyTyped please? I'll update the readme to point there instead if that happens.
from reselect.
Ok will do - I'm not sure on the best way to get it merged but it may help if the PR has been 'approved' by a member of the reselect project...
Until it is merged if you are using tsd you can manually put the PR commit hash in tsd.json to install this declaration file:
"reselect/reselect.d.ts": {
"commit": "7ee8c031f981bfb4fd1dd511d3edf598ab96e5bb"
},
from reselect.
That PR has now been merged.
from reselect.
Thanks
from reselect.
Would you guys be willing to include the typings in the NPM package? The main benefit being that the typings can be managed directly in this repo, and users do not have to go to a third-party source to get typings for this lib. I would be more than willing to implement this.
https://github.com/Microsoft/TypeScript/wiki/Typings-for-npm-packages
from reselect.
@ianks Yes, please do!
from reselect.
After having used the typing for a while, I noticed it isn't playing well with connect
from react-redux
.
Since the props
argument in the Selector<>
function is any
, all component wrappers created by connect
are inferred to have the props be any
. That sucks.
So I'm experimenting with this instead:
type Selector<TInput, TProps, TOutput> = (state: TInput, props?: TProps) => TOutput;
function createSelector<TInput, TProps, TOutput, T1>(selector1: Selector<TInput, TProps, T1>, combiner: (arg1: T1) => TOutput): Selector<TInput, TProps, TOutput>;
function createSelector<TInput, TProps, TOutput, T1, T2>(selector1: Selector<TInput, TProps, T1>, selector2: Selector<TInput, TProps, T2>, combiner: (arg1: T1, arg2: T2) => TOutput): Selector<TInput, TProps, TOutput>;
Seems to work fine. Any comments?
from reselect.
Thanks for the suggestion. I don't know Typescript well enough to be confident in commenting.
@ianks @frankwallis @geon: do any of you want commit access to Reselect to take care of Typescript issues?
from reselect.
@geon that looks good. can you create a minimal example case for this (just to show that that types are retained from connect)?
from reselect.
Here's a semi-realistic example of what our code looks like:
delete_button_component.ts
export type DeleteButtonProps = DeleteButtonStateProps & DeleteButtonDispatchProps;
export type DeleteButtonStateProps = {
disabled: boolean
}
export type DeleteButtonDispatchProps = {
onClick: event => void
}
export function deleteButton({
disabled,
onClick
}: DeleteButtonProps) {
return DOM.button({
disabled,
onClick
}, 'Delete');
}
delete_button_container.ts
type DeleteButtonContainerProps = {
itemId: string
}
const mapStateToProps = createSelector<
// NOTE! 3 types for the input/output instead of 2 as before.
RootState, DeleteButtonContainerProps, DeleteButtonStateProps,
boolean
> (
(state, props) => !!state.items[props.itemId],
(itemExists: boolean) => ({
disabled: !itemExists
})
);
function mapDispatchToProps (dispatch: ReactRedux.Dispatch, props: DeleteButtonContainerProps): DeleteButtonDispatchProps {
return {
onClick: event => dispatch(actions.deleteItem(props.itemId))
};
}
export const DeleteButton = connect(mapStateToProps, mapDispatchToProps)(deleteButton);
Now, calling the container with anything else than DeleteButtonContainerProps
will not compile.
Using it:
function render () {
return DOM.div({}
SomeItemView({
foo: 'foo',
bar: 'bar',
itemId: theItemId
}),
DeleteButton({
itemId: theItemId
})
);
}
We don't use jsx, so I don't really know how to write a more idiomatic example. Seems like nobody else use the DOM api manually. :P
This code has obviously never run, so I'm sure there are some bugs in it. But I think you get the gist.
Without the props typing I suggested, DeleteButton
would accept any extra and missing props.
from reselect.
@ellbee , I'm not sure I should have commit access. I still feel like a react noob. I've only been using it since christmas.
from reselect.
I would be quite unhappy if I had to start specifying all the type parameters
Yeah. For some reason, we didn't get that to work earlier. Possible because we had bad typing in other places. (We migrated to ts with a lot of js already written.) I should try again.
Can I also ask if you are using connect as a decorator or as a plain function
We only use it as a function, since 99% of our components are stateless functions, not classes.
I suppose there really should be a few test cases to ensure the typings work in all the intended situations.
from reselect.
I tried using createSelector
without explicit type parameters. It seems it will work fine, as long as the "primitive" selectors in the arguments are explicitly typed, just like in your example.
Modified example from above (that actually compiles, yay!):
const mapStateToProps = Reselect.createSelector(
(state: RootState, props: DeleteButtonContainerProps) => !!state.items[props.itemId],
(itemExists: boolean) => ({
disabled: !itemExists
})
);
I suppose it would be impossible to not type it explicitly somewhere. In our case, we have a lot ot "primitive" selectors, so it is nice to be able to type them in createSelector
. A trade-off.
from reselect.
So I have given this a try, I did get some compiler errors because I am using the Selector
type as the input to some of my selector creation functions, and these now fail because they are missing a type parameter e.g.
export function createListPropsSelector<TItem>(listStoreSelector: Selector<GlobalState, ListStore>, repositorySelector: Selector<GlobalState, Repository<TItem>>): Selector<GlobalState, ListProps<TItem>>;
Unfortunately it is not possible to specify default values for generic parameters, but hopefully that will be possible soon (see here). If it were possible it sounds like they would have to be at the end of the parameter list so I think that the TProps param should be moved to the end.
I have this working and backwards compatible as follows:
type PropsSelector<TInput, TOutput, TProps> = (state: TInput, props?: TProps) => TOutput;
type Selector<TInput, TOutput> = PropsSelector<TInput, TOutput, any>;
function createSelector<TInput, TOutput, T1, TProps>(selector1: PropsSelector<TInput, T1, TProps>, combiner: (arg1: T1) => TOutput): PropsSelector<TInput, TOutput, TProps>;
function createSelector<TInput, TOutput, T1, T2, TProps>(selector1: PropsSelector<TInput, T1, TProps>, selector2: PropsSelector<TInput, T2, TProps>, combiner: (arg1: T1, arg2: T2) => TOutput): PropsSelector<TInput, TOutput, TProps>;
function createSelector<TInput, TOutput, T1, T2, T3, TProps>(selector1: PropsSelector<TInput, T1, TProps>, selector2: PropsSelector<TInput, T2, TProps>, selector3: PropsSelector<TInput, T3, TProps>, combiner: (arg1: T1, arg2: T2, arg3: T3) => TOutput): PropsSelector<TInput, TOutput, TProps>;
When default generic parameters are available it will be possible to unify PropsSelector
and Selector
If people are already calling createSelector
with the type-parameters then they will get errors due to the missing TProps type parameter, so for back-compatibility I think it is necessary to keep the existing declarations as overrides as well, ie
function createSelector<TInput, TOutput, T1, TProps>(selector1: PropsSelector<TInput, T1, TProps>, combiner: (arg1: T1) => TOutput): PropsSelector<TInput, TOutput, TProps>;
function createSelector<TInput, TOutput, T1>(selector1: Selector<TInput, T1>, combiner: (arg1: T1) => TOutput): Selector<TInput, TOutput>;
from reselect.
I added tests and props typing in a pull-request. Please review: #115
from reselect.
For some reason, i have the typescript compiler complaining that the reselect module is unknown.
I get this error :
Error:(1, 30) TS2307:Cannot find module 'reselect'.
with code
import {createSelector} from 'reselect';
from reselect.
@vjau Can you open a new issue with information on TypeScript version and contents of tsconfig.json? TS2307 can happen for hundreds of different reasons.
from reselect.
I had this error when "module" in my tsconfig.json was set "es6", try importing using
const { createSelector } = require('reselect');
from reselect.
To everyone interested, please help review updated typings: #192
from reselect.
Related Issues (20)
- Investigate potential memory leak issues with `weakmapMemoize` HOT 11
- unstable_autotrackMemoize Errors HOT 1
- How to type redux state and selectors with readonly? HOT 3
- Consider dev mode checks for `x => x` result functions HOT 2
- More Reselect addons to investigate HOT 1
- Add identifiable information to dev mode check log messages HOT 3
- Documentation ignores links in the table of contents entries HOT 1
- Type loss in `createSelector` with inline function declarations passed as separate arguments
- lastResult.deref is not a function (it is undefined) HOT 6
- Better call stack for selector warnings HOT 11
- Unable to use `resultEqualityCheck` with `weakMapMemoize` HOT 3
- Incorrect weakMapMemoize alternative example using useCallback HOT 1
- using createSelector.withTypes prevents build HOT 7
- Question: Why can't we support `createAsyncSelector`? HOT 7
- TypeError: (0 , _reselect.createSelector) is not a function HOT 12
- `weakMapMemoize` with `resultEqualityCheck` is provided empty objects for first call. HOT 3
- Library do not work in Safari < 14.1 HOT 1
- Why the LRUCache implementation is using Array over the Doubly Linked List with Map? HOT 8
- Question: should OutputSelector be used as an InputSelector? HOT 3
- Current documentration loose article about passing parameters HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from reselect.