如何通用地键入 React 组件 props 并扩展通用 props 类型



我有一个元素类型参数化的组件。我想键入此组件,以便您可以指定元素的类型并将 props 限制为该类型。

interface IProps<T> extends T {
elementName: string,
}
class Foo<T> extends React.Component<IProps<T>, {}> {
render() {
const { elementName, ...props } = this.props;
return React.createElement(elementName, {
...props,
});
}
}

例如,当道具的类型AnchorHTMLAttributes时,href是有效的道具,但在HTMLAttributes时则不是。

// Ok
<Foo<AnchorHTMLAttributes<AnchorHTMLElement>> href="foo.com"/>
// Type checker error because `href` is not an attribute of a div
<Foo<HTMLAttributes<HTMLDivElement>> href="foo.com"/>

这是否可能,如果可能,如何?

看起来你想要的类型是:

React.InputHTMLAttributes<HTMLInputElement>

将两个Input换成其他类型的标签。

看起来最通用的约束是:

React.HTMLAttributes<HTMLElement>

然后,您可以将该类型与提供elementName的东西合并。通过约束和elementName,您可以获得:

function Foo<T extends React.HTMLAttributes<HTMLElement>>(
props: T & { elementName: string },
) {
const { elementName, ...otherProps } = props
return React.createElement(elementName, otherProps)
}

或作为类组件:

class Foo<T extends React.HTMLAttributes<HTMLElement>> extends React.Component<
T & { elementName: string }
> {
render() {
const { elementName, ...otherProps } = this.props
return React.createElement(elementName, otherProps)
}
}

用法的工作方式与您似乎期望的一样,尽管您必须提供elementName

function App() {
return <>
<Foo<React.InputHTMLAttributes<HTMLInputElement>>
elementName="input"
value={1}
/> {/* valid */}
<Foo<React.InputHTMLAttributes<HTMLInputElement>>
elementName="input"
href='/foo/bar'
/> {/* Property 'href' does not exist on type */}
</>
}

工作游乐场

尝试使用这种类型,它扩展了 React.HTMLAttributes 并包含来自其他元素的 props:

React.AllHTMLAttributes<unknown>

最新更新