Вопрос о правильном наборе текста для JSX для определения специального компонента

#typescript #jsx #typescript-typings #typescript-types

#typescript #jsx #typescript-typings #typescript-типы

Вопрос:

Я работаю над экспериментальной библиотекой веб-компонентов. Компоненты в основном имеют тип

 type Component<Props> = {
  new(): Props,
  init(props: Props): ...
}
 

и реализован следующим образом

 // a bit simplified
@component('my-component')
class MyComponent {
  @prop()
  someProp = 0

  static init(props: MyComponent) {
    ...
  }
}
 

Теперь я хочу использовать JSX для этого. В реальном мире все немного сложнее, но здесь скажем, что все реквизиты компонентов должны быть необязательными в JSX.

 // a bit simplified
function createElement<Props>(type: Component<Props>, props?: Partial<Props> | null, ...) {
  ...
}
 

Теперь createElement(MyComponent) работает отлично, но <MyComponent/> приведет к ошибке компиляции

«Тип ‘{ }’ не может быть присвоен типу ‘IntrinsicAttributes amp; MyComponent’. Свойство ‘someProp’ отсутствует в типе ‘{ }’, но требуется в типе ‘MyComponent’. ts(2322)»

Как мне исправить это в глобальных наборах JSX или где угодно? MTIA

[Правка — добавлена демонстрация]: Пожалуйста, найдите здесь немного упрощенную демонстрацию (=> см. Ошибка компиляции в строке 39 index.tsx — я предполагаю, что проблема где-то в jsx.d.ts): https://codesandbox.io/s/naughty-platform-8x3q5?file=/src/index.tsx

PS: Кстати, простое изменение someProp = 0 на someProp? = 0 не является полезным решением.

Комментарии:

1. Не удается воспроизвести конкретную ошибку, на которую вы ссылаетесь — из вашего примера похоже, что MyComponent не содержит каких-либо требуемых методов : Type 'MyComponent' is missing the following properties from type 'ElementClass': render, context, setState, forceUpdate, and 3 more . Можете ли вы создать пример TS playground? typescriptlang.org/play

2. Спасибо mbdavis за вашу помощь. Я добавил ссылку на небольшую демонстрацию в вопросе выше.

3. В вашей демо-версии нет ошибки, createElement возвращает значение null, ошибки нет. Не могли бы вы предоставить более подробную информацию?

4. На самом деле в самой последней строке моей демонстрации действительно есть ошибка типа (см.: <MyComponent /> ) … вот в чем весь вопрос. Я совершенно уверен, что мой ответ ниже соответствует действительности (но не уверен на 100%).

Ответ №1:

Я думаю, то, что я пытаюсь здесь сделать, в настоящее время невозможно с JSX (по крайней мере, без дополнительного вызова функции, например export default convert(MyComponent) ).

В пространстве имен JSX вы можете настроить interface ElementClass и interface ElementAttributesProperty сообщить JSX, как получить конкретный тип реквизита компонента класса. Что слишком ограничено для моей демонстрации.

В моей демонстрации извлечение типа реквизита компонента сложнее, чем можно настроить с помощью ElementAttributesProperty , ИМХО.

Пожалуйста, дайте мне знать, если я ошибаюсь в этом предположении или если у вас есть дополнительные комментарии или предложения.

Ответ №2:

Ваша прагма JSX должна быть примерно такой:

 /** @jsx createElement */

const appendChild = (parent, child) => {
  if (Array.isArray(child))
    child.forEach(nestedChild => appendChild(parent, nestedChild))
  else
    parent.appendChild(
      child.nodeType ? child : document.createTextNode(child)
    )
}

export const createElement = (tag, props, ...children) => {
  const element = document.createElement(tag)

  Object.entries(props || {}).forEach(([name, value]) => {
    if (name.startsWith('on') amp;amp; name.toLowerCase() in window)
      element.addEventListener(name.toLowerCase().substr(2), value)
    else
      element.setAttribute(name, value.toString())
  })

  children.forEach(child => {
    appendChild(element, child)
  })

  return element
}


document.getElementById('root').appendChild(
  <div>Hello</div>
)

 

💻 Проверьте эту демонстрацию.

Я не знаю о вашем виртуальном dom, я не могу сказать, что с ним может быть не так.

🎈 Мои советы:

  1. Сначала попробуйте заставить его работать без виртуального dom
  2. Не забудьте добавить его в document
  3. Перед их обработкой убедитесь, что ваши реквизиты не являются null или undefined .