3

What I know

When using TypeScript with angular's ui state, I can provide "type assertion" with the UI-Router definitely typed library.

Using this, I can inject $state and have code similar to the following

function myCtrl($state: ng.ui.IStateService){
    // Some code
}

This gives me correct autocompletion/error reporting for $state's methods.

So far, this is all fine.

The problem

When I try to access a property of params like the following

function myCtrl($state: ng.ui.IStateService){
    // Trying to access a property of $state.params
    var example = $state.params.example;
}

I get an error saying:

Property 'example' does not exist on IStateParamsService

because quite rightly, TypeScript doesn't know about this property.

I considered trying:

Defining my own Interface that extends ng.ui.IStateService

interface IMyState extends ng.ui.IStateService{
    params: {
        example: string;
    };
}

Then set the type to my interface

function myCtrl($state: IMyState){
    var example = $state.params.example;
}

This gets rid of the error.

What is the correct type to use for $state?

Should I be defining my own interface like in my example?

Community
  • 1
  • 1
Matt Lishman
  • 1,817
  • 2
  • 22
  • 34
  • *some inspiration how could you use TS and angularJS [here](http://stackoverflow.com/q/30501735/1679310)* – Radim Köhler May 23 '16 at 10:16
  • @RadimKöhler Thanks. I am using importing/exporting classes etc. I just tried to keep it simple for the sake of this question. Useful link though. – Matt Lishman May 23 '16 at 10:19
  • *Just a hint before you'll get your answer... I am using `class` with the `static $inject` notation... hint ;)* – Radim Köhler May 23 '16 at 10:19
  • @RadimKöhler I use `class` and `static $inject` notation in my production code. However, I still need to annotate the parameters correctly. I just thought using it here adds unnecessary confusion. – Matt Lishman May 23 '16 at 10:25
  • If you can show me some real.. broken .. code (best in plunker) I will help you... as far as I could... Other words... snippets in your question are not clear to me.. not sure what is not working. I do use UI-Router, TS and AngularJS... so some experience could be shared – Radim Köhler May 23 '16 at 10:26
  • @RadimKöhler I've edited the question to try make it a little clearer. I want to know what type `$state` should be defined as. When using `ng.ui.IStateService` I get the error posted in my question. – Matt Lishman May 23 '16 at 10:40
  • I think your approach is good. That is the way I do it and I don't see any other. Although a bit more 'untyped' will be if you declare it as `any`, this way you won't need to create an interface extra – iberbeu May 23 '16 at 11:13
  • Sorry, for not understand your issue at first look.. I hope my answer will show you how to.. good luck with UI-Router ;) (similar trick I applied here: http://stackoverflow.com/a/33763652/1679310) – Radim Köhler May 23 '16 at 11:38

2 Answers2

5

With Typescript, we really can easily extend a contract, coming with UI-Router .d.ts.

So this is the original definition (UI-Router d.ts. file):

// a state object
interface IStateService {
    ...
    params: IStateParamsService;
    ...
// params
interface IStateParamsService {
    [key: string]: any;
}

And we can just introduce into our custom .d.ts these lines

declare module angular.ui
{
    export interface IStateParamsService { example?: string; }
}

And that will now give us ability to consume $state and its params with example:

MyMethod($state: ng.ui.IStateService)
{
    let x = this.$state.params.example;
    ...
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
3

$state.params are of type IStateParamsService and if you look at the type signature you can read that it is an indexable type.

Indexable types have an index signature that describes the types we can use to index into the object, along with the corresponding return types when indexing.

The described type of IStateParamsService is

(key: string): any

which means something like, "you can store objects of type any(everything is an any) and read the objects by the key (or index or you-name-it, this is where the name indexable type comes from) of type string".

here some code:

// this gives us an object of type IStateParamsService
let params = $state.params;

// params is a indexable type
// we want the object stored at index 'example'
let example = params['example'];
// or
let example = $state.params['example'];

more informations about interfaces and types can be found here.

Lusk116
  • 791
  • 1
  • 6
  • 17
  • 2
    Please edit with more information. Code-only and "try this" answers are discouraged, because they contain no searchable content, and don't explain why someone should "try this". – Paritosh Sep 01 '16 at 05:51