TypeScript的React类型化为所有可能的HTML元素提供了很多接口。但有时,你的浏览器、你的框架或你的代码比可能的东西要领先一点。
比方说,你想在Chrome中使用最新的图片功能,并懒散地加载你的图片。一个渐进式的增强,所以只有了解情况的浏览器才知道如何解释。其他浏览器足够强大,不会在意。
<img src="/awesome.jpg" loading="lazy" alt="What an awesome image" />
你的TypeScript JSX代码?错了。
function Image({ src, alt }) {
// 💥 Property 'loading' does not exist...
return <img src={src}
alt={alt}
loading="lazy" />
}
为了防止这种情况,我们可以用我们自己的属性扩展可用的接口。TypeScript的这一特性被称为声明合并。
创建一个@types 文件夹,并在其中放置一个jsx.d.ts 文件。改变你的TypeScript配置,使你的编译器选项允许额外的类型。
{
"compilerOptions": {
...
/* Type declaration files to be included in compilation. */
"types": ["@types/**"],
},
...
}
我们重新创建确切的模块和接口结构。
- 该模块被称为
'react'。 - 接口是
ImgHTMLAttributes<T> extends HTMLAttributes<T>
我们从原始类型中知道。在这里,我们添加我们想拥有的属性。
import 'react'
declare module 'react' {
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
loading?: 'lazy' | 'eager' | 'auto';
}
}
当我们在做的时候,让我们确保我们不会忘记alt文本!
import 'react'
declare module 'react' {
interface ImgHTMLAttributes<T> extends HTMLAttributes<T> {
loading?: 'lazy' | 'eager' | 'auto';
+ alt: string;
}
}
好多了!TypeScript将采用原始定义并合并你的声明。你的自动完成可以给你所有可用的选项*,*当你忘记了一个alt文本时,会出错。
我们可以使用同样的方法,当我们希望styled-jsx ,与TypeScript兼容。style TypeScript不承认jsx 和global 标签的属性。让我们来改变这一点。
declare module 'react' {
interface StyleHTMLAttributes<T> extends React.HTMLAttributes<T> {
jsx?: boolean;
global?: boolean;
}
}
当与Preact一起工作时,事情就有点复杂了。原始的HTML类型是非常慷慨的,不像React的类型那么具体。这就是为什么我们在定义图像的时候要更明确一些。
declare namespace JSX {
interface IntrinsicElements {
"img": HTMLAttributes & {
alt: string,
src: string,
loading?: 'lazy' | 'eager' | 'auto';
}
}
}
这确保了alt 和src 都是可用的,并设置了可选属性loading 。
不过,技术是一样的。声明合并,它对命名空间、接口和模块都有效。