使用原生 Web 组件时,Typescript 报错 "Property does not exist on type 'JSX.IntrinsicElements'"。

10
我正在使用React和Typescript开发一个项目,但我想开始在我的项目中使用本地Web组件,逐步淘汰我的一些React组件。
当我尝试在某些JSX中包含person-info组件时,我收到了这个错误。
Property does not exist on type 'JSX.IntrinsicElements'

我看了一些其他有这些问题的问题,但是似乎都与本地Web组件无关。

当我在项目中使用我的Web组件时,如何使Typescript和React可以很好地配合?

PersonInfo.mjs

const css = `
  <style>
    :host([hidden]) { display: none; }
    :host {
      align-items: center;
      display: grid;
      font-weight: normal;
      grid-gap: var(--spacing-size-a) var(--spacing-size-a);
      grid-template-areas:
        'picture heading'
        'picture sub-heading';
      grid-template-columns: auto 1fr;
      justify-items: start;
    }
    div {
      grid-area: picture;
    }
    h1, h2 {
      margin: 0;
      padding: 0;
    }
    h1 {
      align-self: end;
      font-size: var(--l-text-size);
      font-weight: normal;
      grid-area: heading;
      text-transform: capitalize;
    }
    h2 {
      align-self: start;
      font-size: var(--m-text-size);
      grid-area: sub-heading;
    }
    ion-icon {
      font-size: 56px;
    }
  </style>
`

const html = `
  <div>
    <ion-icon name="md-contact"></ion-icon>
  </div>
  <h1>Heading</h1>
  <h2>Sub-heading</h2>
`

class PersonInfo extends HTMLElement {
  static get observedAttributes () {
    return [
      'heading',
      'subHeading',
      'size'
    ]
  }

  constructor () {
    super()

    this.attachShadow({mode: 'open'})
    this.shadowRoot.appendChild(template.content.cloneNode(true))
  }

  connectedCallback () {
    this.shadowRoot.querySelector('h1').innerText = this.getAttribute('heading')
    this.shadowRoot.querySelector('h2').innerText = this.getAttribute('subHeading')
  }

  get heading () {
    return this.getAttribute('heading')
  }
  set heading (newValue) {
    this.setAttribute('heading', newValue)
    this.shadowRoot.querySelector('h1').innerText = newValue
  }

  get subHeading () {
    return this.getAttribute('subHeading')
  }
  set subHeading (newValue) {
    this.setAttribute('subHeading', newValue)
    this.shadowRoot.querySelector('h2').innerText = newValue
  }

  get size () {
    return this.getAttribute('size')
  }
  set size (newValue) {
    this.setAttribute('size', newValue)
  }
}

const template = document.createElement('template')
template.innerHTML = `${css}${html}`

window.customElements.define('person-info', PersonInfo)

导入语句

import '../../common/WebComponents/PersonInfo.mjs'

在JSX中的使用

<main>
  <person-info
    heading='Bruce Wayne'
    subHeading="I'M BATMAN!"
  />
</main>

1
我从未在我的TypeScript / React项目中创建过Web组件,但我怀疑如果您增强JSX.IntrinsicElements并添加具有其HTMLProps类型的personinfo,则它将起作用。您可以在文档中阅读有关如何增强的内容。 - Shanon Jackson
1个回答

23

我在这里找到方法,解决了这个特定错误。

import * as React from 'react'

declare global {
    namespace JSX {
        interface IntrinsicElements {
            'person-info': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>;
        }
    }
}

接着我遇到了另一个错误,这是因为我在组件上使用了自定义属性。感谢 Shanon 的评论,我找到了解决方法,并最终得到了这段代码,我把它导入了我的App.tsx文件中。

import * as React from 'react'

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'person-info': PersonInfoProps
    }
  }
}

interface PersonInfoProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {
  heading: string,
  subHeading: string,
  size?: string
}

1
但是,对于使用CRA创建的React应用程序,它会引发另一个错误:“ES2015模块语法优先于自定义TypeScript模块和命名空间@typescript-eslint/no-namespace”。 - hipertracker
确实,如果您在eslint中使用此规则,则会引发错误,尽管typescript本身没有问题。这个修复的原因是它扩展了JSX的现有命名空间,以包括任何自定义Web组件。我没有看到解决问题的另一种方法,除非修改JSX本身的原始定义(我认为这是一个坏主意)。如果您想在确保此工作的同时使@typescript-eslint/no-namespace规则对存储库的其余部分保持活动状态,我建议仅忽略此文件的eslint规则。 - Christopher Bradshaw
我也遇到了同样的eslint警告,看起来这个语法在typescript中即将被弃用。不幸的是,我找不到一个可行的语法。有没有比我更擅长TS的人能提供解决方案? - Netsab612

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接