0

We use angular-ui-router.js v 0.2.18 + angular-ui-router.d.ts v 1.4.6 (typescript v 1.8.36.0).

So we use IStateProvider to configure navigation from one state to another.
Often we need to pass some state parameters from father state to child state.
Config:

.state(States.MeasureDetail, {
    parent: States.OperatorView,
    templateUrl: '/App/Business/Kanban/BuildAndCureKanban/Views/MeasureDetail.html',
    controller: Controllers.MeasureDetailController,
    controllerAs: 'measureDetailCtrl',
    params:
    {
        machine: null,
        material: null
    }
})

In father controller:

this.$state.go(States.MeasureDetail, {
        machine: this.currentMachine,
        material: this.currentMaterial
     });

In child controller:

constructor(
    private buildAndCureService: Services.IBuildAndCureService,
    private $state: ng.ui.IStateService,
    private eventManager: _Common.Services.IEventManager){

    this.machine = $state.params["machine"];
    this.material = $state.params["material"];
}

The problem
Neither params property nor IStateParameterService interface are strongly typed: you access by key and obtain an any type.

params?: any;

interface IStateParamsService {
    [key: string]: any;
}

This is a weakness that, in big projects with many developers, has already brought to runtime issues.

The question
I know that is possible to extend IStateParameterService like the example in this post to add a typed field, but the solution is once for all states, whereas I need a solution to add typed fields state by state.
How can I extended IStateParameterService to have something like:

interface IStateParamsService {
    CustomParam<T>?: T;
}

?
Thanks.

ilcorvo
  • 446
  • 5
  • 18
  • Just define ICustomStateParams per state and use it instead of IStateParameterService. Do you have problems with this approach? – Estus Flask Mar 12 '18 at 11:24
  • @estus Could you, please, make clearer you solution by adding some code example? Better if you could modify my use case. Thank you. – ilcorvo Mar 13 '18 at 14:28

1 Answers1

0

There is no need to extend IStateParameterService globally here, exactly because it is supposed to be local.

Since $stateParams has been deprecated in 1.x, it's reasonable to use $state for migration purposes and thus extend IStateService directly instead of IStateParameterService:

interface IMeasureDetailStateService extends ng.ui.IStateService {
    params: { 
        CustomParam?: string;
    }
}

...

constructor(
    private buildAndCureService: Services.IBuildAndCureService,
    private $state: IMeasureDetailStateService,
    private eventManager: _Common.Services.IEventManager)
{
    $state.params.CustomParam;
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Thank you, estus, your snippet makes clear the injection of the parameters. Anyway, parameters' definition (in my question snippet 1) and setting them before state navigation (in my question snippet 2) still remains outside typing control. Could you please suggest how to fix this weakness? – ilcorvo Mar 20 '18 at 11:18
  • You'll need to add similar `interface IMeasureDetailState extends ng.ui.IStateService` and specify this type for `.state` object. I'm not sure it's possible to do that for anonymous object, so likely it should be `const mdState:IMeasureDetailState = ...; $stateProvider.state(States.MeasureDetail, mdState)`. At this point typing becomes clumsy and inefficient, I'd suggest to skip types there. ui-router is loosely typed, you can't do anything with it without rewriting its types. $stateProvider and $state methods are supposed to use generics to type `params` and `data`, and they don't. – Estus Flask Mar 20 '18 at 11:58