Пространство имен TypesScript - Dynami c определение полей (JS до TS) - PullRequest
1 голос
/ 12 марта 2020

Я пытаюсь преобразовать этот JavaScript код из atom / etch в TypeScript, не нарушая publi c API.

Он определяет как dom-function, так и dom-array of functions (оба имеют одно и то же имя dom):

// called by the following loop
function dom (tag, props, ...children) {
// ...
}

const HTML_TAGS = [
  'a', 'abbr'] // ... has more elements though
// similarly SVG-Tags is defined

// finds the array of functions
for (const tagName of HTML_TAGS) {
  dom[tagName] = (props, ...children) => {
    return dom(tagName, props, ...children)
  }
}

for (const tagName of SVG_TAGS) {
  dom[tagName] = (props, ...children) => {
    return dom(tagName, props, ...children)
  }
}

module.exports = dom

Какая эквивалентная версия TypeScript этого?

Другие пакеты используют dom, например dom.a(tag, props, childern) пример , или используя @jsx etch.dom пример

Запустив dts-gen, я получаю пространство имен с именем dom, которое содержит все функции, определенные внутри for-l oop.

export namespace dom {
    function a(props: any, children: any): any;
    function abbr(props: any, children: any): any;
//...
}

Вот моя ветка .

1 Ответ

1 голос
/ 12 марта 2020

Я предполагаю, что вы создаете файл определения типа dom.d.ts для dom.js.

Пространство имен не является правильным типом для dom. Пространство имен TS во время выполнения JS представляется как простой объект. Но dom является одновременно вызываемой функцией и объектом с дополнительными свойствами. Таким образом, вы должны использовать интерфейс с вызываемой подписью для представления dom в TS.

dom.d.ts

interface EtchElement<T extends string, P = any> {
  tag: T;
  props: P;
  children: any[];
  ambiguous: any[];
}

type EtchCreateElement<T extends string, P> = (props: P, ...children: any[]) => EtchElement<T, P>;

interface EtchDOM {
  <T extends string, P>(tag: T, props: P, ...children: any[]): EtchElement<T, P>;
  div: EtchCreateElement<"div", any>;
  // ... more tags here
}

declare const dom: EtchDOM;

export = dom;

Поддержка JSX

Теперь, если вы также намереваетесь поддерживать использование JSX, вам сначала нужно прочитать официальное руководство JSX , чтобы узнать требования. Я выделю эту выдержку:

Intrinsi c элементы ищутся в специальном интерфейсе JSX.IntrinsicElements. [...] если этот интерфейс присутствует, то имя элемента intrinsi c ищется как свойство в интерфейсе JSX.IntrinsicElements.

Соберите вместе, вот скромный тип определение, которое работает:

interface EtchElement<T extends string, P = any> {
  tag: T;
  props: P;
  children: any[];
  ambiguous: any[];
}

type EtchCreateElement<T extends string, P> = (props: P, ...children: any[]) => EtchElement<T, P>;

interface EtchDOM {
  <T extends string, P>(tag: T, props: P, ...children: any[]): EtchElement<T, P>;
  div: EtchCreateElement<"div", JSX.IntrinsicElements["div"]>;
  // ... more tags here
}

declare const dom: EtchDOM;

export = dom;

declare global {
  namespace JSX {
    interface Element extends EtchElement<any, any> {}
    interface IntrinsicElements {
      div: any; // constraint on props of "div" element
    }
  }
}

...