问题描述
我正在开发一个实验性的 Web 组件库。 组件基本上都是类型
type Component<Props> = {
new(): Props,init(props: Props): ...
}
并实现如下
// a bit simplified
@component('my-component')
class MyComponent {
@prop()
someProp = 0
static init(props: MyComponent) {
...
}
}
现在我想为此使用 JSX。在现实世界中,事情有点复杂,但在这里假设所有组件 props 在 JSX 中都是可选的。
// a bit simplified
function createElement<Props>(type: Component<Props>,props?: Partial<Props> | null,...) {
...
}
现在 createElement(MyComponent)
工作正常,但 <MyComponent/>
会导致编译错误
“类型 '{ }' 不能分配给类型 'IntrinsicAttributes & MyComponent'。属性 'someProp' 在类型 '{ }' 中缺失,但在类型 'MyComponent' 中是必需的。ts(2322)”
我该如何在全局 JSX 类型或其他地方解决这个问题? MTIA
[编辑 - 添加演示]:请在此处找到一个简化的演示(=> 参见 index.tsx 的第 39 行中的编译错误 - 我猜问题出在 jsx.d.ts 中):https://codesandbox.io/s/naughty-platform-8x3q5?file=/src/index.tsx
PS:顺便说一句,只是将 someProp = 0
更改为 someProp? = 0
并不是一个有用的解决方案。
解决方法
我想,我在这里尝试做的事情目前在 JSX 中是不可能的(至少在没有额外的函数调用的情况下是不可能的,例如 export default convert(MyComponent)
)。
在 JSX 命名空间中,您可以配置 interface ElementClass
和 interface ElementAttributesProperty
来告诉 JSX 如何检索类组件的具体 props 类型。这对于我的演示来说太有限了。
在我的演示中,组件 props 类型的检索比通过 ElementAttributesProperty
进行配置更复杂,恕我直言。
如果我对这个假设有误,或者您有其他意见或建议,请告诉我。
,你的 JSX pragma 应该是这样的:
/** @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') && 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>
)
? 检查这个demo。
我不知道你的虚拟 dom 我不能说它有什么问题。
? 我的建议:
- 先尝试让它在没有虚拟 dom 的情况下工作
- 不要忘记将其附加到文档中
- 在处理 props 之前,请确保它们不为 null 或 undefined。