在 Preact 和 typescript 中使用 web 组件
Posted
技术标签:
【中文标题】在 Preact 和 typescript 中使用 web 组件【英文标题】:Using web-components within Preact and typescript 【发布时间】:2020-07-15 19:59:37 【问题描述】:我在Preact 中使用custom-elements 又名网络组件。问题是 Typescript 抱怨没有在 JSX.IntrinsicElements
中定义元素 - 在这种情况下是 check-box
元素:
<div className=styles.option>
<check-box checked=this.prefersDarkTheme ref=this.svgOptions.darkTheme/>
<p>Dark theme</p>
</div>
错误信息(路径省略):
ERROR in MyComponent.tsx
[tsl] ERROR in MyComponent.tsx(50,29)
TS2339: Property 'check-box' does not exist on type 'JSX.IntrinsicElements'.
我遇到了以下可能的解决方案,不幸的是没有工作:
-
https://***.com/a/57449556/7664765 - 这是一个与问题无关的答案,但它涵盖了我的问题
我已尝试将以下内容添加到我的 typings.d.ts
文件中:
import * as Preact from 'preact';
declare global
namespace JSX
interface IntrinsicElements
'check-box': any; // The 'any' just for testing purposes
我的 IDE 将导入部分和 IntrinsicElements
显示为灰色,这意味着它没有被使用(?!)并且它无论如何都没有工作。我仍然收到相同的错误消息。
-
https://***.com/a/55424778/7664765 - 同样对于反应,我尝试将其“转换”为 preact,我得到了与 1 相同的结果。
我什至在 squoosh 项目中找到了由 google 维护的 file,他们在其中执行以下操作来“填充”支持:
在与组件相同的文件夹中,包含以下内容的
missing-types.d.ts
文件,基本上与我的设置相同,但使用index.ts
文件而不是check-bock.ts
,并且他们使用的是较旧的 TS 版本v3.5.3
:
declare namespace JSX
interface IntrinsicElements
'range-input': htmlAttributes;
我假设他们的构建没有失败,那么它是如何工作的以及如何正确定义自定义元素以在 preact / react 组件中使用它们?
我目前正在使用typescript@v3.8.3
和preact@10.3.4
。
【问题讨论】:
【参考方案1】:这里是正确使用的属性,否则在传递key
时会报错。
declare global
namespace JSX
interface IntrinsicElements
'xx-element1': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>; // Normal web component
'xx-element2': React.DetailedHTMLProps<React.HTMLAttributes<HTMLInputElement>, HTMLInputElement>; // Web component extended from input
【讨论】:
【参考方案2】:好的,我设法使用module augmentation 解决了它:
declare module 'preact/src/jsx'
namespace JSXInternal
// We're extending the IntrinsicElements interface which holds a kv-list of
// available html-tags.
interface IntrinsicElements
'check-box': unknown;
使用HTMLAttributes
接口,我们可以告诉 JSX 哪些属性可用于我们的自定义元素:
// Your .ts file, e.g. index.ts
declare module 'preact/src/jsx'
namespace JSXInternal
import HTMLAttributes = JSXInternal.HTMLAttributes;
interface IntrinsicElements
'check-box': HTMLAttributes<CheckBoxElement>;
// This interface describes our custom element, holding all its
// available attributes. This should be placed within a .d.ts file.
declare interface CheckBoxElement extends HTMLElement
checked: boolean;
【讨论】:
这是未来的自己。 哇,是的,我又来了。希望我能多次支持这个答案。【参考方案3】:使用 typescript 4.2.3 和 preact 10.5.13,以下是使用属性定义自定义标签名称的方法:
declare module 'preact'
namespace JSX
interface IntrinsicElements
'overlay-trigger': OverlayTriggerAttributes;
interface OverlayTriggerAttributes extends preact.JSX.HTMLAttributes<HTMLElement>
placement?: string;
区别:
模块为'preact'
(必须加引号)。
命名空间是JSX
。
IntrinsicElements
值类型是扩展 HTMLAttributes 的接口。
它通过名称 preact.JSX.HTMLAttributes
扩展 HTMLAttributes。
它将基本元素类型提供为HTMLElement
,以像事件侦听器一样填充道具/属性中的 eventTarget 类型。如果适用,您也可以输入SVGElement
。
【讨论】:
这适用于我使用 TypeScript 4.3.5 和 Preact 10.5.15,但需要注意的是,我还需要在声明之前import 'preact'
。【参考方案4】:
有一种更好的方法可以做到这一点,而无需手动绑定事件。
您可以使用 @lit-labs/react
的 createComponent
将 web 组件包装到 React 组件。
import * as React from "react";
import createComponent from "@lit-labs/react";
import Slrange from "@shoelace-style/shoelace/dist/components/range/range.js";
export const Range = createComponent(React, "sl-range", Slrange,
change: "sl-change" // map web component event to react event
);
import Range from "./SlRange";
export default function App()
return (
<div className="App">
<Range max=6 min=2 step=2></Range>
</div>
);
【讨论】:
它仍然是一个 Web 组件,只是被抽象掉了以上是关于在 Preact 和 typescript 中使用 web 组件的主要内容,如果未能解决你的问题,请参考以下文章
使用 Preact + Typescript 的类型安全事件处理程序
最新的 preact 和 typescript 模块传递了错误的类型
preact-cli/babel/typescript - 让 Symbol.iterator 和 [...spread] 正常工作