developit / preact-redux

:loop: Preact integration for Redux (no shim needed!)
https://npm.im/preact-redux
MIT License
288 stars 26 forks source link

Add TypeScript typings #20

Closed rand0me closed 7 years ago

rand0me commented 7 years ago

Hi! It would be nice to have TypeScript typings in this very useful package. If you've find an issues in the PR, feel free to point me :point_left:

rand0me commented 7 years ago

Hi, folks! This PR fixes #6, so if anyone can merge, I will be very thankful :star2:

geon commented 7 years ago

I get an error:


ERROR in /Users/[REDACTED]/src/static/ts/typings-custom/preact-redux/index.d.ts
(161,14): error TS2415: Class 'Provider' incorrectly extends base class 'Component<ProviderProps, {}>'.
  Types of property 'render' are incompatible.
    Type '(props: ProviderProps) => VNode' is not assignable to type '(props?: (ProviderProps & ComponentProps<this>) | undefined, state?: {} | undefined, context?: an...'.
      Types of parameters 'props' and 'props' are incompatible.
        Type '(ProviderProps & ComponentProps<this>) | undefined' is not assignable to type 'ProviderProps'.
          Type 'undefined' is not assignable to type 'ProviderProps'.

I commented it out, since I figured I could live without it, but then the typing is not recognized at all:

error TS7016: Could not find a declaration file for module 'preact-redux'.
rand0me commented 7 years ago

Which version of Preact you use? I have types working with 8.2.1. Here is my example:


interface IOwnProps {
    index: number;
}

interface IStateProps {
    type: string;
    place: string;
    visible: boolean;
}

export const MyComponent = (props: IOwnProps & IStateProps) => <div>{ props.type }</div>;

const mapProps = (o: IOwnProps) => o;
const mapState = (s: IState, p: IOwnProps) => ({ ...s.list[p.index] });

export default connect(mapState, null, mapProps)(MyComponent);
Yen commented 7 years ago

I might be missing something here, but this does not decay the props like react-redux does.

Take the example here

interface LabelProps {
    content: string;
}

const Label = (props: LabelProps) => (
    <h1>{props.content}</h1>
);

const mapStateToProps = (state: State) => ({
    content: state.theTextForTheLabel
});

const ConnectedLabel = PreactRedux.connect(mapStateToProps)(Label);

const App = () => (
    <PreactRedux.Provider store={store}>
        <ConnectedLabel /> // error here
    </PreactRedux.Provider>
)

Error:

'Type '{}' is not assignable to type 'LabelProps & ComponentProps<Component<LabelProps, any>>'.
  Type '{}' is not assignable to type 'LabelProps'.
    Property 'content' is missing in type '{}'.'

This is because the type of ConnectedLabel is Preact.ComponentConstructor<LabelProps, any> instead of Preact.ComponentConstructor<{}, any> or something similar.

I am not well enough versed to fully understand how the react-redux libray does it, but it seems like the InferableComponentEnhancerWithProps interface there is the key. It is removing the keys returned from the mapStateToProps function from the required props of the connected type.

I am of course coming from react-redux so preact-redux might work in a different way here and this is actually the expected behaviour, but I don't believe that to be so.

rand0me commented 7 years ago

Hey, @Yen, could you check updated typings, I will be very thankful if You do :grey_exclamation:

developit commented 7 years ago

Let's merge this and see how it does in the wild :)

cvuorinen commented 7 years ago

In case anyone else runs into the same issue I'm having using preact-redux with TypeScript, AFAICT the current AnyComponent typing in preact seems to be causing connect to not recognize component classes correctly and gives error TS2345: Argument of type 'typeof MyComponent' is not assignable to parameter of type 'AnyComponent...

There is a PR open for typings overhaul which would probably fix this issue https://github.com/developit/preact/pull/621

But in the mean time, I found that a workaround to disable the error is to just tell TS that it's AnyComponent with e.g. connect(...)(MyComponent as AnyComponent<MyProps, {}>)