我有一个元素类型参数化的组件。我想键入此组件,以便您可以指定元素的类型并将 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>