代码之家  ›  专栏  ›  技术社区  ›  CMTV

TypeScript类型提示类似于`document.createElement`

  •  0
  • CMTV  · 技术社区  · 1 年前

    我试图创造类似的 createElement 我为我的项目自定义DOM(带有自定义节点)的方法,该方法将nodeName作为参数并返回相应Node的实例。

    import { Node } from "./tree";
    
    export class DOM
    {
        private defs: Record<string, new () => Node>;
    
        constructor(nodeDefs: Record<string, new () => Node>)
        {
            for (const [nodeName, NodePrototype] of Object.entries(nodeDefs))
                this.defs[nodeName] = NodePrototype;
        }
    
        create(nodeName: keyof typeof this.defs)
        {
            const newNode = new this.defs[nodeName]();
            newNode.name = nodeName;
    
            return newNode;
        }
    }
    

    代码运行良好,但我没有得到方便的提示,知道哪些节点名称可用,返回类型总是 Node ,不是我创建的节点的确切类型。

    我应该如何更改上面的代码以使提示正常工作?

    const dom = new DOM({
        paragraph: Paragraph,
        text: Text
    });
    
    const myP = dom.create('paragraph'); // Correct type hints here!
    
    1 回复  |  直到 1 年前
        1
  •  1
  •   hoangdv    1 年前

    让我们创建你的DOM类 create 方法变得通用:

    type InstanceTypeOf<T> = T extends new () => infer I ? I : never; // get type from a constructor
    
    export class DOM<T extends Record<string, new () => Node>> { // Genneric T, infer constructor param
      private readonly defs: T = {} as T;
    
      constructor(nodeDefs: T) {
        for (const [nodeName, NodePrototype] of Object.entries(nodeDefs) as Array<[keyof T, T[string]]>) { // fix typing error
          this.defs[nodeName] = NodePrototype;
        }
      }
    
      create<K extends Extract<keyof T, string>>(nodeName: K) { // generic, infer by nodeName type
        const newNode = new this.defs[nodeName]();
        newNode.name = nodeName;
    
        return newNode as InstanceTypeOf<T[K]>; // casting
      }
    }
    
    const dom = new DOM({
      paragraph: Paragraph,
      text: Text,
    });
    
    const p = dom.create('paragraph');
    //    ?^ const p: Paragraph