dphilipson / typescript-fsa-reducers

Fluent syntax for defining typesafe reducers on top of typescript-fsa.
MIT License
220 stars 16 forks source link

`case` and `cases` functions have type error. #32

Closed arx-8 closed 4 years ago

arx-8 commented 5 years ago

Thank you for creating an awesome package!

I tried to Usage code, however I got a following error message.
Could you tell me how to fix this error?

Error message

$ npm run tsc

> error-reproduction@1.0.0 tsc X:\dev\error-reproduction
> tsc --noEmit

src/index.ts:32:9 - error TS2345: Argument of type '{ (payload: boolean, meta?: { [key: string]: any; } | null | undefined): Action<boolean>; type: string; match: (action: AnyAction) => action is Action<boolean>; }' is not assignable to parameter of type '{ (payload: false, meta?: { [key: string]: any; } | null | undefined): Action<false>; type: string; match: (action: AnyAction) => action is Action<false>; }'.
  Types of property 'match' are incompatible.
    Type '(action: AnyAction) => action is Action<boolean>' is not assignable to type '(action: AnyAction) => action is Action<false>'.
      Type predicate 'action is Action<boolean>' is not assignable to 'action is Action<false>'.
        Type 'Action<boolean>' is not assignable to type 'Action<false>'.
          Type 'boolean' is not assignable to type 'false'.

32   .case(setIsFrozen, (state, isFrozen) => ({ ...state, isFrozen }))
           ~~~~~~~~~~~

src/index.ts:32:23 - error TS7006: Parameter 'state' implicitly has an 'any' type.

32   .case(setIsFrozen, (state, isFrozen) => ({ ...state, isFrozen }))
                         ~~~~~

src/index.ts:32:30 - error TS7006: Parameter 'isFrozen' implicitly has an 'any' type.

32   .case(setIsFrozen, (state, isFrozen) => ({ ...state, isFrozen }))
                                ~~~~~~~~

src/index.ts:35:13 - error TS2769: No overload matches this call.
  The last overload gave the following error.
    Type '{ (payload: number, meta?: { [key: string]: any; } | null | undefined): Action<number>; type: string; match: (action: AnyAction) => action is Action<number>; }' is not assignable to type '{ (payload: string, meta?: { [key: string]: any; } | null | undefined): Action<string>; type: string; match: (action: AnyAction) => action is Action<string>; }'.
      Types of property 'match' are incompatible.
        Type '(action: AnyAction) => action is Action<number>' is not assignable to type '(action: AnyAction) => action is Action<string>'.
          Type predicate 'action is Action<number>' is not assignable to 'action is Action<string>'.
            Type 'Action<number>' is not assignable to type 'Action<string>'.
              Type 'number' is not assignable to type 'string'.

35   [setName, addBalance],
               ~~~~~~~~~~

  node_modules/typescript-fsa-reducers/dist/index.d.ts:9:5
    9     cases<P>(actionCreators: Array<ActionCreator<P>>, handler: Handler<InS, OutS, P>): ReducerBuilder<InS, OutS>;
          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The last overload is declared here.

Found 4 errors.

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! error-reproduction@1.0.0 tsc: `tsc --noEmit`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the error-reproduction@1.0.0 tsc script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\arx8\AppData\Roaming\npm-cache\_logs\2019-08-31T09_35_44_520Z-debug.log

Reproducible code

error-reproduction.zip

Reporter's environment

Expect result

arx-8 commented 4 years ago

Is this repository dead? :sob:

dphilipson commented 4 years ago

Hi @arx-8 ! This repository is not dead! I'm just very sorry to say I didn't see your first report in August. I am looking into it now.

It looks like this has been broken since 2.6, where changes were made to checking function covariance (see the release notes), which is quite a long time so I suppose not many people are using this method.

I'll take a look at fixing it.

dphilipson commented 4 years ago

Hi again @arx-8 ! Actually, I think things might be working fine. Your repro sees an error because the handler in .cases doesn't return a state. If I modify your sample code to add the line return state, e.g.

const reducer2 = reducerWithInitialState(INITIAL_STATE).cases(
  [setName, addBalance],
  (state, payload) => {
    // Payload has type SetNamePayload | AddBalancePayload.
    // ...
    console.log(state)
    console.log(payload)
    return state
  }
)

Then it correctly typechecks and payload is correctly inferred as string | number.

I agree that TypeScript's error message in this case was particularly unhelpful. I'll update the README to show a return value in the .cases example.

arx-8 commented 4 years ago

@dphilipson Sorry for my late reply.

I am very sorry that return state is the basic knowledge of Redux. :bowing_man: And I tried again. It is working correctly with TypeScript 3.7! error-reproduction(fixed).zip

Thank you for your kind response & Update README!