我可以通过代理实例化TypeScript类吗?

时间:2017-11-18 06:34:02

标签: typescript types sublimetext3 implicit index-signature

注意:我已经更新了这个问题,希望能让事情更清楚。

我试图通过名为elemTypes的代理对象来实例化类。此对象是我要用于基于类似DOM的树结构以编程方式构建对象的类的引用列表。我是TypeScript的新手,所以我希望我在这里只是缺少一些简单的东西?

以下是代码:

type elemDef = {
    type: string,
    name: string,
    childNodes: object[]
}

class Elem {
    childNodes: object[]
    constructor (childNodes: object[]) {
        this.childNodes = childNodes
    }
}

class Div extends Elem {
    constructor (childNodes: object[]) {
        super(childNodes)
    }
}

class Form extends Elem {
    constructor (childNodes: object[]) {
        super(childNodes)
    }
}

class Input extends Elem {
    name: string
    constructor (childNodes: object[], nodeDef: elemDef) {
        super(childNodes)
        this.name = nodeDef.name
    }
}

const div = {
    type: 'Div',
    childNodes: [
        {
            type: 'Form',
            childNodes: [
                {
                    type: 'Input',
                    name: 'username',
                    childNodes: []
                },
                {
                    type: 'Input',
                    name: 'password',
                    childNodes: []
                },
            ]
        }
    ]
}

// I expect that I am doing this part wrong:
const elemTypes = {
    Div,
    Form,
    Input
}

const makeElem = (nodeDef: elemDef) => {
    const childNodes:object[] = []

    nodeDef.childNodes.forEach((childNodeDef: object): void => {
        const element = new elemTypes[childNodeDef.type](childNodeDef)
        childNodes.push(element)
    })

    const element = new elemTypes[nodeDef.type](nodeDef)

    return element
}

// This line just demonstrates that the code is working:
console.log(JSON.stringify(makeElem(div), null, 2))

上面一行的输出是:

{
  "childNodes": {
    "type": "Div",
    "childNodes": [
      {
        "type": "Form",
        "childNodes": [
          {
            "type": "Input",
            "name": "username",
            "childNodes": []
          },
          {
            "type": "Input",
            "name": "password",
            "childNodes": []
          }
        ]
      }
    ]
  }
}

我遇到的问题是,SublimeText 3给了我这个错误:

Element implicity has a type 'any' type because the type
'{ Div: typeof Div; Form: typeof Form; Input: typeof Input };
 has no index signature;

我试过通过阅读TypeScript文档并查看类似问题的一些StackOverflow答案来解决这个问题,但我似乎无法找到我在这里做错了什么。

但是有没有人知道是否有办法定义meta对象将停止在我的IDE中隐藏任何错误? (注意:我不想在我的.ts-config.js文件中关闭隐式错误。)

我不想在ts-config。{/ p>中关闭任何隐含的规则

任何想法都赞赏。

2 个答案:

答案 0 :(得分:1)

  

它在javascript中运行,因此必须使用 更多 错综复杂的 方式打字稿。


如果"我不知道你想要达到的目标,但这就是你如何做到的!" 看起来是一个可接受的答案开始,继续阅读。

  

在解决主要问题之前,请执行以下所有更改。

//Be specific. Change all the "object" type annotations to "elemDef". Doing 
//so, the compiler will be able to validate if the type of an argument you are    
//trying to pass to your constructors contains all the properties existent 
//in an "elemDef" object.

type elemDef = {
    type: string;
    name?: string; //<- not all elements have a name, make it optional
    childNodes: elemDef[]; //<- you have a recursive structure.
}

class Elem { 
    readonly type: string;//<- the type of an element is not supposed to change
    childNodes: elemDef[];
    constructor (childNodes: elemDef[]) {
        this.childNodes = childNodes;
        this.type = "Elem";
    }
}


class Div extends Elem {
    readonly type: string;
    constructor (childNodes: elemDef[]) {
        super(childNodes);
        this.type = "Div";
    }
}

class Form extends Elem {
    readonly type: string;
    constructor (childNodes: elemDef[]) {
        super(childNodes);
        this.type = "Form";
    }
}

输入构造函数中 nodeDef 的参数类型必须为 elemDef &amp; < em> { name string } 所以它不会接受为参数任何没有名称的elemDef。

class Input extends Elem {
    readonly type: string;
    name: string;
    constructor (childNodes: elemDef[], nodeDef: elemDef & { name : string }) {
        super(childNodes);
        this.name = nodeDef.name;
        this.type = "Input";
    }
}
  

那么,还有什么遗漏?

这是对象的索引签名:

{ [key: type1]: type2 }

编译器推断 elemTypes 的类型为:

const elemTypes: {
    Div: typeof Div;
    Form: typeof Form;
    Input: typeof Input;
}

因此有必要提供一个从字符串映射到函数的签名,但是当你这样做时,编译器会告诉你可以使用 new 运算符来调用一个函数缺少构造函数签名。从第二个问题开始:

//this is a type that defines a signature for a generic constructor for elements
type ElementConstructor<T> = {
    new(childNodes: elemDef[]): T;
}

现在我们提供签名并使用 ElementConstructor 类型来转换 const elemTypes 中的每个类:

const elemTypes : { [index: string]: ElementConstructor<Elem> } = {
    Div: Div as ElementConstructor<Div>,
    Form: Form as ElementConstructor<Form>,
    Input: Input as ElementConstructor<Input>
};
  

最后

只需在 makeElement 函数中进行一些调整:

// In your original snippets, you were passing objects to constructor in 
// the forEach but all your constructors take arrays as arguments 
const makeElem = (nodeDef: elemDef) => {
    const childNodes: elemDef[] = [];

    nodeDef.childNodes.forEach((childNodeDef: elemDef): void => {
        const element = new elemTypes[childNodeDef.type]([childNodeDef]); // <- put inside an array
        childNodes.push(element);
    });

    const element = new elemTypes[nodeDef.type]([nodeDef]);  //<- put inside an array
    return element;
}

答案 1 :(得分:-1)

不完全确定,但也许你可以尝试这样的事情并看看它是否有帮助?

const proxy: {person: Being} = {
    person: Being
}