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

Type mismatch with angular 5.2 and typescript 2.6.2 #709

Closed
sandangel opened this issue Jan 11, 2018 · 8 comments
Closed

Type mismatch with angular 5.2 and typescript 2.6.2 #709

sandangel opened this issue Jan 11, 2018 · 8 comments

Comments

@sandangel
Copy link
Contributor

sandangel commented Jan 11, 2018

I'm submitting a...


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

What is the current behavior?

consider the following snippet

export interface RouterStateUrl {
  url: string;
  queryParams: Params;
  params: Params;
}

export interface RootState {
  router: RouterReducerState<RouterStateUrl>;
}

export const reducers: ActionReducerMap<RootState> = {
  router: routerReducer
};

tsconfig.json:

{
  "compileOnSave": false,
  "compilerOptions": {
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "noUnusedParameters": true,
    "noUnusedLocals": true,
    "strict": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2016",
      "dom"
    ]
  }
}

Do note that strict: true

It worked with typescript 2.5.3, but after updating to typescript 2.6.2 (which is now supported in angular 5.2.0), compiler has show an error and project can not be successfully built anymore

Error:(22, 14) TS2322: Type '{ router: <T = RouterStateSnapshot>(state: RouterReducerState<T>, action: RouterAction<any, Route...' is not assignable to type 'ActionReducerMap<RootState, Action>'.
  Types of property 'router' are incompatible.
    Type '<T = RouterStateSnapshot>(state: RouterReducerState<T>, action: RouterAction<any, RouterStateSnap...' is not assignable to type 'ActionReducer<RouterReducerState<RouterStateUrl>, Action>'.
      Types of parameters 'state' and 'state' are incompatible.
        Type 'RouterReducerState<RouterStateUrl> | undefined' is not assignable to type 'RouterReducerState<RouterStateUrl>'.
          Type 'undefined' is not assignable to type 'RouterReducerState<RouterStateUrl>'.

Expected behavior:

App continue to work with typescript 2.6.2

Minimal reproduction of the problem with instructions:

clone this repo ngrx-bug-report and serve --aot

git clone https://github.com/sandangel/ngrx-bug-report.git

ng serve --aot

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

Chrome 63, Ubuntu 16.04, npm 5.6, node 8.9.4, ngrx 4.1.1

Other information:

@christophjohannsdotter
Copy link

Confirming, i have this problem, too!
iI you use
"typescript": "~2.5.3" along with angular 5.2 it works again.

@sandangel
Copy link
Contributor Author

seem like typescript 2.6.2 break many other libs, switched back to 2.5.3 now

@markgoho
Copy link

markgoho commented Jan 11, 2018

@sandangel It looks like this error is displaying when strictFunctionTypes is set to true. Can you confirm by setting strict to false and just enabling strictFunctionTypes?

@sandangel
Copy link
Contributor Author

I confirm that it work when set strict to true and strictFunctionTypes to false

@tytskyi
Copy link

tytskyi commented Jan 12, 2018

@brandonroberts @MikeRyanDev this is not only problem of the router, but basically with approach of typed actions.
If you bump angular, install typescript ^2.6 and add "strictFunctionTypes": true, to platform/example-app/tsconfig.app.json.
Then yarn run example:start will not compile and will give a lot of errors.

See: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html

@duartealexf
Copy link

I confirm that I run into the same problem of type incompatibility, and I also have created an issue (#611 (comment)) that is unanswered.

I don't agree to the fact that we need to set "strictFunctionTypes": false to compile properly.
IMHO that flag unsets a benefit we can get from the compiler... and ngRx should not require that.

@sandangel
Copy link
Contributor Author

sandangel commented Feb 4, 2018

I have modified ofType implementation and solved error in effects. Then using REDUCER_TOKEN instead of ActionReducerMapp as a work around.

import { Action } from '@ngrx/store';
import { filter } from 'rxjs/operators';

export function ofType<T extends Action>(...allowedTypes: string[]) {
  return filter((action: Action): action is T => {
    return allowedTypes.some(type => type === action.type);
  });
}
export const REDUCER_TOKEN = new InjectionToken<ActionReducerMap<State>>('Registered Reducers');

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule.withServerTransition({ appId: 'my-app' }),
    BrowserAnimationsModule,
    LayoutModule,
    MaterialModule,
    SharedModule,
    RouterModule.forRoot([]),
    ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }),
    /* use token here */
    StoreModule.forRoot(REDUCER_TOKEN),
    EffectsModule.forRoot([RouterEffects]),
    !environment.production ? StoreDevtoolsModule.instrument() : [],
    StoreRouterConnectingModule.forRoot({
      stateKey: 'router'
    })
  ],
  bootstrap: [AppComponent],
  providers: [
    { provide: RouterStateSerializer, useClass: CustomSerializer },
    // Provide reducer map here
    { provide: REDUCER_TOKEN, useFactory: () => ({ router: routerReducer }) }
  ]
})
export class AppModule {}

Or you can use ActionReducerMap<any, any> to ignore type checking

@sandangel
Copy link
Contributor Author

sandangel commented Mar 5, 2018

hi, I still have this problem and I suppose that this issue was not fixed by #841
The source of error is the contravariantly check in ts 2.6 with ActionReducer type and routerReducer type:

export interface ActionReducer<T, V extends Action = Action> {
    (state: T | undefined, action: V): T;
}
// and
export declare function routerReducer<T = RouterStateSnapshot>(
  state: RouterReducerState<T>, 
  action: RouterAction<any, T>
): RouterReducerState<T>;

Contravariance in the argument type means A <: B implies (B -> T) <: (A -> T) (A and B flipped sides).

which mean:

  • type T | undefined of ActionReducer have to be assignable to type of state parameter in routerReducer
    and
  • action: { type: string } have to be assignable to action: RouterAction<any, T>

both are not possible since undefined is not assignable to RouterReducerState and string is not assignable to string literal

I suggest to fix this issue we have to change the signature of routerReducer to

export declare function routerReducer<T = RouterStateSnapshot>(
  state: RouterReducerState<T> | undefined, // add undefined
  action: RouterAction<any, T>
): RouterReducerState<T>;

and change the default type in ActionReducerMap<T, V = Action> to ActionReducerMap<T, V = any>;

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

No branches or pull requests

7 participants