Jthorpe Jthorpe - 1 month ago 9
TypeScript Question

Interface for object whose members are classes

I have a module which defines several classes which take type parameters (

<T>
) and implement an interface (
my_interface
).

// [my_module.ts]
import {my_interface} from ".\typings.d.ts"
export class Class_A <T> implements my_interface {
blah blah blah;
}
export class Class_B <T> implements my_interface {
blah blah blah;
}


and I have a
.d.ts
file that defines interfaces for the class instances:

// [typings.d.ts]
export interface my_interface <T> {
blah:blah;
}


I want to add an interface that describes the module as a whole, but the following raises a "TS2304: Cannot find name 'T'." error:

// [typings.d.ts]
export interface MY_MODULE {
Class_A: my_interface<T>;
Class_B: my_interface<T>;
}


and the following raises an "TS2314: Generic type 'my_interface' requires 1 type argument(s)" error:

// [typings.d.ts]
export interface MY_MODULE {
Class_A: my_interface;
Class_B: my_interface;
}


Is there a way to create an interface (
MY_MODULE
) to describe the object that is imported when the compiled JS code is imported via:

var my_module:MY_MODULE = require("my_module")

Answer

I have to wonder if you're using generics meaningfully here. Anyway, the past of least resistance to do what you'd like to do is this: make MY_MODULE generic.

export interface MY_MODULE<T> {
    Class_A: my_interface<T>;
    Class_B: my_interface<T>;
}

The parameter will then resolve correctly. In your import you would then type it as

var my_module:MY_MODULE<type-here> = require("my_module")

if you don't care what gets fed into it, go ahead and do

var my_module:MY_MODULE<any> = require("my_module")

This has some implications. This means that type_A and type_B are both generic off of the same type. Is this intended? If not, then rather than using :my_interface<T> in your type annotation you should fill in the type you're interested in type_A and type_B working on. If you don't care, you can again use any.

Would you like to suppress supplying type information until it's used? Perhaps type A and B are collections of some sort and you would like them to carry the type they're initialized on onto later function calls. You can achieve this as well, but you'll need to use a function such as:

interface ExampleModule {
    Class_A: <T> (param: T) => my_interface<T>
}

or a constructor such as:

interface ExampleModule {
    Class_A: { new<T>(): my_interface<T> };
}

and then use the generated object.