piotrwitek / typesafe-actions

Typesafe utilities for "action-creators" in Redux / Flux Architecture
https://codesandbox.io/s/github/piotrwitek/typesafe-actions/tree/master/codesandbox
MIT License
2.41k stars 98 forks source link

ActionType is returning `never` #226

Closed iansan5653 closed 4 years ago

iansan5653 commented 4 years ago

Description

The ActionType helper is returning never instead of the correct mapping, despite using a very simple actions file.

I'm probably doing something incorrectly, but if so, I can't find it.

Mandatory info

I'm trying to, but it's not working:

import {ActionType} from "typesafe-actions";
import * as actions from "./actions";

export type RootAction = ActionType<typeof actions>; // results in `never`

declare module "typesafe-actions" {
  interface Types {
    RootAction: RootAction;
  }
}

How to Reproduce

This is reproduced with simply the types.d.ts file above, and the actions.ts file below:

import {createAction} from "typesafe-actions";
import * as api from "utilities/api";

export const example = createAction("EXAMPLE", () => 3);

CodeSandbox Link

https://codesandbox.io/s/crazy-snyder-meokt

Expected behavior

I expect the type of RootAction to be {type: "EXAMPLE"}.

Project Dependencies

christophemenager commented 4 years ago

Hello,

I think you should write :

export const example = createAction("EXAMPLE", () => 3)();

You have forgotten the () at the end !

piotrwitek commented 4 years ago

Thanks @christophemenager you are right! It's missing () at the end!

mnbattaglia commented 4 years ago

Hey @piotrwitek . I was banging my head with this issue for more than two hours. I have a working app in v4 and wanted to migrate to v5. I'm using an actor creator with a plain object like this example (https://github.com/piotrwitek/typesafe-actions#actiontype) and then using ActionType to create my RootAction type. Finally, I'm creating my reducer by providing generics like this:

import {ActionType, createAction, createReducer} from 'typesafe-actions'

export type State = Readonly<{
    some: string,
}>

const actions = {
    action1: createAction('action1'),
    nested: {
        action2: createAction('action2'),
        moreNested: {
            action3: createAction('action3'),
        },
    },
};
export type RootAction = ActionType<typeof actions>;
export const reducer = createReducer<State, RootAction>({some: "test"})
    .handleAction(actions.action1, (state, action) => {
        return {
            ...state,
        }
    })

This will cause the following errors in the handleAction method:

Error:(18, 19) TS2345: Argument of type '<TPayload = undefined, TMeta = undefined>() => ActionCreatorBuilder<"action1", TPayload, TMeta>' is not assignable to parameter of type '((...args: any[]) => never) | ((...args: any[]) => never)[]'.
  Type '<TPayload = undefined, TMeta = undefined>() => ActionCreatorBuilder<"action1", TPayload, TMeta>' is not assignable to type '(...args: any[]) => never'.
    Type 'EmptyActionCreator<"action1">' is not assignable to type 'never'.
Error:(18, 37) TS7006: Parameter 'state' implicitly has an 'any' type.
Error:(18, 44) TS7006: Parameter 'action' implicitly has an 'any' type.

Luckily, I found this thread and the reason was the missing () at the end of action creation. Is my reasoning ok? Don't you think this should be added in the migration guide?

Thanks!

mnbattaglia commented 4 years ago

Sorry @piotrwitek , after re-reading the migration guide, in step 3 I can see in the "after" code of createAction there is actually a () at the end. Maybe you can highlight it somehow for idiots like me so they don't waste so much time

piotrwitek commented 4 years ago

@mnbattaglia you can send a PR with edit in the docs and I will merge ;)