#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/play2. Спасибо 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, я не могу сказать, что с ним может быть не так.
🎈 Мои советы:
- Сначала попробуйте заставить его работать без виртуального dom
- Не забудьте добавить его в document
- Перед их обработкой убедитесь, что ваши реквизиты не являются null или undefined .