4
votes

I have an interface defining an index signature:

interface MethodCollection {
    [methodName: string]: (id: number, text: string) => boolean | void;
}

Everything's good here, any method I add to such an object will have their parameter types recognized correctly:

var myMethods: MethodCollection = {
    methodA: (id, text) => {
        // id: number
        // text: string
    }
}

Now, I need to add a type parameter to these functions:

interface MethodCollection {
    [methodName: string]: <T>(id: number, text: string, options: T) => boolean | void;
}

The moment I do this, the TypeScript compiler barfs up:

Parameter 'text' implicitly has 'any' type

Parameter 'options' implicitly has 'any' type

Parameter 'id' implicitly has 'any' type

And indeed, neither can IntelliSense trace the correct types any longer, they all become implicit any:

var myMethods: MethodCollection = {
    methodA: (id, text, options) => {
        // id: any
        // text: any
        // options: any
    }
}

Why is this happening? How can I use generic methods with an index signature? I'm using Visual Studio 2013, my project is set to use TypeScript version 1.6.

1
I'm using TypeScript 1.8.6 in VS 2015 and that code works fine for me. Intellisense doesn't get broken or anything. The released version 1.8.5 of TypeScript for VS 2013 a few days ago. there are quite a few changes. Can you upgrade and see if it works?rgvassar
@rgvassar The issue also seems to exist in 1.8.5. At least, when I type tsc -v into the Package Manager Console or into cmd, they both give 1.8.5.John Weisz
I'd post a bug on their github. Maybe they can fix it with their next release.rgvassar
@rgvassar Well according to you, it's already fixed in 1.8.6, no? (: If you are certain the issue is fixed in 1.8.6, I'll try to jam that version into VS2013.John Weisz
I don't know why they call it 1.8.6 on Visual Studio 2015, but in the release notes, it says it's the same release.rgvassar

1 Answers

2
votes

You can make the type inference work by making the interface generic, and specify it when creating the variable.

interface MethodCollection<T> {
    [methodName: string]: (id: number, text: string, options: T) => boolean | void;
}

var myMethods: MethodCollection<string> = {
    methodA: function(id, text, options) {
        // id :number,
        // text: string,
        // options: string
    }
}

With VSCode and tsc 1.9.0 (current typescript@next), it's the only way it works.

That wouldn't allow you to have different types for different methods though.

You can however give an optional type to the MethodCollection.

var myMethods: MethodCollection<string | boolean> = {
    methodA: function(id, text, options) { 
        // options is string | boolean
    }
}