Inner types or hybrid namespace/class functionality?

Topics: General, Language Specification
Oct 12, 2012 at 12:57 PM
Edited Oct 12, 2012 at 12:57 PM

I have a problem with creating a TypeScript definition file for the OpenLayers project (http://openlayers.org).

In OpenLayers there are classes that are named exactly like a namespace (and typically serve as base class for all classes in that namespace).

For example there is a class OpenLayers.Geometry and a class OpenLayers.Geometry.Point.

As far as I know this currently can't be supported in TypeScript since it is not possible for a type to have inner types (so Point would be a inner type of Geometry) and it is also not possible to have a class that has the exact same name as a module/namespace.

Is there any plan to enable this kind of behavior? Is there already a way to model that kind of class library?

Thanks in advance!

Oct 13, 2012 at 4:10 AM
Edited Oct 13, 2012 at 4:11 AM

Here's one way you might implement such a model. This should help you declare the equivalent TS for existing code.

The key thing is the use of 'new' in the type annotation for the Geometry.Point property.

class GeometryPoint {
    x: number;
    y: number;

    constructor () {
        this.x = 23;
        this.y = 24;
    }
}

class Geometry {

    static Point : new () => GeometryPoint = GeometryPoint;

}

var p = new Geometry.Point();
Oct 13, 2012 at 4:39 PM
Edited Oct 13, 2012 at 5:04 PM

The solution is a real good start, however there still remains a problem. What happens if I have multiple constructor overloads?

I think with your solution I can only bind one constructor :(.

Oh and one more thing: If I have static fields/properties on GeometryPoint those also get lost.

It really starts to look like it's not possible to create definition files for OpenLayers :(.

module OpenLayers {
    class GeometryPoint {
        x: number;
        y: number;

        constructor () {
            this.x = 23;
            this.y = 24;
        }

static getsLost: number;
  } export class Geometry { static Point : new () => GeometryPoint; static Point : new (x: number, y: number) => GeometryPoint; // error } }
Developer
Oct 13, 2012 at 11:44 PM
Edited Oct 13, 2012 at 11:46 PM

You might consider something like this:

interface OLGeometry {
    id: string;
    parent: OLGeometry;
    ...
}

interface OLPoint extends OLGeometry {
    x: number;
    y: number;
    ...
}

interface OLCollection extends OLGeometry {
    components: OLGeometry[];
    componentTypes: string[];
    ...
}

declare var OpenLayers: {
    Geometry: {
        Point: {
            new (): OLPoint;
            new (x: number, y: number): OLPoint;
        };
        Collection: {
            new (components: OLGeometry[]): OLCollection;
        };
        fromWKT(wkt: string): OLGeometry;
        ...
    };
    ...
};

This is the pattern we're using in 'lib.d.ts' and 'jquery.d.ts'. The one drawback is that it doesn't allow you to use TypeScript's class syntax to create classes that derive from the OpenLayers classes. I don't know if that is a scenario.

We'll definitely continue to think about solutions to this as the language evolves.

Anders