Typescript: Using the type of a static inner class

我与影子孤独终老i 提交于 2020-08-01 12:39:32

问题


I'm trying to write a class that exposes an inner data structure to its consumers, a data structure that the class itself will be using.

Example:

class Outer {
    static Inner = class {
        inInner: number
    };

    constructor(public inner: Outer.Inner) { }
}

The problem here is that Outer.Inner is not recognized as a type.

The only answers that I've found are workarounds (in Typescript playground). I'm wondering if there are any elegant ways of doing this.


Usecase:

I have a bunch of Actions that are sent over WebSockets between client and server. Each Action has its own Data inner class. The Data class itself is used elsewhere on the server. I could separate this into two classes (or an interface), like Action1, Action1Data, but I think that Action1.Data is a more readable design.


回答1:


Your second "workaround" is the prefer way to go:

class Outer {
    constructor(public inner: Outer.Inner) { }
}

namespace Outer {
    export class Inner {
        inInner: number
    };
}

// Spec
let outer1 = new Outer({ inInner: 3 });

let outerInner = new Outer.Inner();
let outer2 = new Outer(outerInner);

There are three types of declarations in TypeScript: namespace, type, and value. You would use namespace to organize types and value.

http://www.typescriptlang.org/docs/handbook/declaration-merging.html

It does not reduce readability because there is no concept of an "Inner Class" in TypeScript.

Remember that the class syntax is just sugar of es5 prototypal inheritance. How would you represent an inner class in prototypal inheritance? Do you put is as an instance variable? or under Outer.prototype.???

what it ends up in es5 is something like this:

var Outer = function Outer(...) { ... }
Outer.Inner = function Inner() { ... }

If you look at it, the Outer in Outer.Inner is only served as a "namespace" to hold the Inner class.




回答2:


I found a better workaround for this, that even allows the inner class to access the private members of the outer class, like you would expect in a C#-like language. You can actually easily get the type of the static property with the typeof operator. This small modification to your example works:

class Outer
{
    static Inner = class
    {
        inInner: number = 0;
    };

    constructor(public inner: typeof Outer.Inner.prototype) { }
}

But referring to the type as typeof Outer.Inner.prototype gets cumbersome really quickly, so add in this underneath and you can simply refer to it as Outer.Inner as you'd like:

namespace Outer
{
    export type Inner = typeof Outer.Inner.prototype;
}

Combine this with another workaround to allow us to put decorators on the class by making it not an anonymous class and we end up with a fully functional true inner class:

class Outer
{
    static Inner = (() =>
    {
        @decoratable()
        class OuterInner
        {
            inInner: number = 0;
        }
        return OuterInner;
    })();

    constructor(public inner: Outer.Inner) { }
}

namespace Outer
{
    export type Inner = typeof Outer.Inner.prototype;
}


来源:https://stackoverflow.com/questions/42864291/typescript-using-the-type-of-a-static-inner-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!