Sebastian Sebastian - 11 days ago 7
TypeScript Question

Named Constructors and Nested Types in TypeScript Library Definition File - "Duplicate Identifier" Error

I am trying to create a TypeScript library definition file for an existing Javascript library. What's specifically challenging is that we have "named constructors" in our library and nested types.

In Javascript you can do this, e.g.:

var some = new MyModule.SomeClass(); //some is of type 'MyModule.SomeClass'
var some2 = new MyModule.SomeClass.WithValue("value"); //some2 is of the same type as some


The problem comes when there is also an inner enumeration defined in the class like this:

var enumValue = MyModule.SomeClass.SomeEnum.VALUE_A;


I have it working with nested classes and interfaces, however for some reason the typescript compiler chokes when I try to declare a nested enumeration. This is what I have for the above scenario in some
dummylib.d.ts
file:

declare module MyModule {
export interface SomeClass_Interface {
foo: number;
}

export module SomeClass {
export interface InnerClass { bar: string; }
//enum SomeEnum { VALUE_A, B, C }
}

export var SomeClass: {
new (): MyModule.SomeClass_Interface;
WithValue: {
new (bar: string): MyModule.SomeClass_Interface;
};
};
}


The above works great1 and compiles, but as soon as I comment in the
SomeEnum
the compiler gives
Duplicate identifier 'SomeClass'
at the line of the variable declaration. Is this a compiler bug (I am using 0.9.1.1) because the compiler thinks it has to create a declaration because of the enumeration constants or am I doing something wrong?

How can I write a definition file in order to support nested types/named constructors and nested enumerations?

Note that this question is specifically about library definitions. I am not trying to create new classes like this with typescript, I would like to use an existing library instead that cannot be modified.

1well, I had to rename the interface to use the suffix, but this at least works and does not influence the behavior). I was not able to get it to work with the interface using the same name as the module and the variable declaration, although from my understanding from this discussion, this should actually work. It didn't in all my tests, though.

Answer

You could model it like this:

declare module MyModule {
    export class SomeClass {
        static WithValue: {
            new (bar: string): SomeClass;
        };
    }

    export module SomeClass {
        export interface InnerClass { bar: string; }
        export enum SomeEnum { VALUE_A, B, C }
    }
}

Unfortunately there isn't any other way to model an object with both enum members and construct signatures.

Comments