admin管理员组

文章数量:1186135

I'm working with a project that uses React and Typescript, but I want to start using native web components in my project to phase out some of my React components.

I'm getting this error when I try to include use a person-info component in some of my JSX.

Property does not exist on type 'JSX.IntrinsicElements'

I've looked at some of the other questions that have had these issues, but none of them seem to have anything to do with native web components in particular.

How do I get Typescript and React to play nicely when I use my web components in my project?

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 statement

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

Usage in JSX

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

I'm working with a project that uses React and Typescript, but I want to start using native web components in my project to phase out some of my React components.

I'm getting this error when I try to include use a person-info component in some of my JSX.

Property does not exist on type 'JSX.IntrinsicElements'

I've looked at some of the other questions that have had these issues, but none of them seem to have anything to do with native web components in particular.

How do I get Typescript and React to play nicely when I use my web components in my project?

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 statement

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

Usage in JSX

<main>
  <person-info
    heading='Bruce Wayne'
    subHeading="I'M BATMAN!"
  />
</main>
Share Improve this question asked Mar 29, 2019 at 19:34 Christopher BradshawChristopher Bradshaw 2,7755 gold badges27 silver badges41 bronze badges 1
  • 1 Iv'e never created a web-component in my typescript / react project but i suspect if you augment JSX.IntrinsicElements and add personinfo with the type of its HTMLProps it will work. you can read about how to augment in the documentation. – Shanon Jackson Commented Mar 29, 2019 at 19:48
Add a comment  | 

2 Answers 2

Reset to default 28

I figured out after going here how to get this particular error to go away.

import * as React from 'react'

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

I got another error after that, however, due to the custom attributes I use on my component. Thanks to Shanon's comment, I figured out how to fix that too and ended up with this final code that I just imported in my App.tsx file.

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
}

If anyone is getting the same error with Preact you can take a similar approach as the accepted answer, but the difference is that JSX sits under the preact namespace.

declare global {
  namespace preact {
    namespace JSX {
      interface IntrinsicElements {
        'person-info': {
          // your props here
        }
      }
    }
  }
}

本文标签: