1

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

我正在尝试通过一个名为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.

任何想法表示赞赏。

4

2 回答 2

1

它在 javascript 中工作,因此它也必须在 复杂的 方式Typescript 中工作。


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

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

//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";
    }
}

Input构造函数中的参数nodeDef的类型必须是elemDef & { 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;
}
于 2017-11-19T16:41:35.917 回答
-1

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

const proxy: {person: Being} = {
    person: Being
}
于 2017-11-18T06:53:46.257 回答