1

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.

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

I wasn't trying to mix enum members and constructs. I was looking for nesting enumerations inside classes just like in your example which seems to work perfectly! I discarded this approach initially, because unfortunately WebStorm 7.0.2 does have some problems right now with this syntax, hower tsc.exe is happy and VS, too, so I can file a bug against WS! Thanks a lot!
I cannot get this to work with generics. (That's why I discarded that approach initially, IIRC). As soon as I want SomeClass to be generic, the class/module approach does not work anymore for me. I posted another question here
OK, for those who read this - the fact that this does not work with generics is actually a bug in 0.9.1.1 and is fixed in newer (beta) releases.
0

This seems to fulfill your requirements:

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

    interface InnerClass { bar: string; }

    export class SomeClass implements SomeClass_Interface {
        foo: number;
        public static WithValue(bar: string): void;
        public static SomeEnum: { VALUE_A, B, C };
        public static InnerClass: InnerClass;
        // this works, too (no need for extra interface):
        // public static InnerClass: { bar: string; };
    }
}

All this works:

var some1: MyModule.SomeClass = new MyModule.SomeClass();
var some2: MyModule.SomeClass = new MyModule.SomeClass.WithValue("value");
var enumValue = MyModule.SomeClass.SomeEnum.VALUE_A;
var stringValue: string = MyModule.SomeClass.InnerClass.bar;
var numberValue1: number = some1.foo;
var numberValue2: number = some2.foo;

Unfortunately this does not:

var enumValue2: MyModule.SomeClass.SomeEnum;

It creates an error on SomeClass: Error:(13, 26) TS2305:Module 'MyModule' has no exported member 'SomeClass'.

It also may not be perfect regarding the named constructor. I don't understand the named constructor enough to judge this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.