如何使用TypeScript和React的Web组件
在上一篇文章中,我们学习了如何在React中使用Web组件。React最近增加了对Web Components的实验性支持,使我们的React应用能够利用庞大的Web Components生态系统。我们也可以在TSX/TypeScript模板中使用Web Components,为我们的组件提供类型检查。
在我们的例子中,我们将使用前一个教程中的相同的警报Web组件:

为了在我们的React组件中使用警报,我们导入该组件并添加x-alert 标签:
import React, { useState } from 'react';
import './alert.js';
export default function App() {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!show)}>toggle alert</button>
<x-alert hidden={show} status="success" closable oncloseChange={() => setShow(!show)}>
This is a Web Component in React
</x-alert>
</div>
);
}
随着最近对自定义元素的支持,我们现在可以在我们的Web组件元素上设置属性和监听事件。然而,如果我们使用TypeScript,我们可能会在我们的TSX文件中看到一些错误,就像下面这样。

在运行时,React将与我们的Web组件正确工作。然而,TypeScript不能对我们的TSX模板进行类型检查,因为它不知道如何找到我们相关标签的CustomElement类引用。我们可以将我们的标签添加到JSX.IntrinsicElements 全局接口,这将把x-alert 与XAlert 类引用联系起来:
import React, { useState, DOMAttributes } from 'react';
import { XAlert } from './alert.js';
import './alert.js';
type CustomElement<T> = Partial<T & DOMAttributes<T> & { children: any }>;
declare global {
namespace JSX {
interface IntrinsicElements {
['x-alert']: CustomElement<XAlert>;
}
}
}
使用TypeScript泛型,我们可以将我们的Custom Element类XClass ,并结合到ReactDOMAttributes 。这将添加React事件类型,如onClick 到我们的元素。现在,如果我们看一下我们的元素,我们应该看到下面的情况:

我们的组件不能识别我们的Web组件在用户点击关闭按钮时发出的closeChange 事件。然而,我们可以利用TypeScript模板字面类型来轻松地定义哪些事件是可用的。
type CustomEvents<K extends string> = { [key in K] : (event: CustomEvent) => void };
type CustomElement<T, K extends string> = Partial<T & DOMAttributes<T> & { children: any } & CustomEvents<`on${K}`>>;
declare global {
namespace JSX {
interface IntrinsicElements {
['x-alert']: CustomElement<XAlert, 'closeChange' | 'openChange'>;
}
}
}
使用模板字面类型,我们可以创建一个字符串类型的列表,并生成一个新的字符串类型列表,其前缀为React所需的on 。然后我们可以把我们的事件字符串传递给CustomEvents 类型,它将为我们添加函数签名。所以现在我们在React和TSX的Web组件上对我们的自定义事件进行了类型检查。
import React, { useState, DOMAttributes } from 'react';
import { XAlert } from './alert.js';
import './alert.js';
type CustomEvents<K extends string> = { [key in K] : (event: CustomEvent) => void };
type CustomElement<T, K extends string> = Partial<T & DOMAttributes<T> & { children: any } & CustomEvents<`on${K}`>>;
declare global {
namespace JSX {
interface IntrinsicElements {
['x-alert']: CustomElement<XAlert, 'closeChange' | 'openChange'>;
}
}
}
export default function App() {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(!show)}>toggle alert</button>
<x-alert hidden={show} status={'success'} closable oncloseChange={() => setShow(!show)}>
This is a Web Component in React
</x-alert>
</div>
);
}
有了一点TypeScript泛型和模板字面类型的魔力,我们可以使用TypeScript、React和Web组件创造一个优秀的开发者体验。