Issue
I have a component where the element type is parameterized. I'd like to type this component so you can specify the type of the element and constrain the props to that type.
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,
});
}
}
For example, href
is a valid prop when the type of the props is AnchorHTMLAttributes
but not when it's 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"/>
Is this possible and if so, how?
Solution
Looks like type you want is:
React.InputHTMLAttributes<HTMLInputElement>
Swap out both Input
's for other types of tags.
And it looks like the most generic constraint would be:
React.HTMLAttributes<HTMLElement>
Then you can merge that type with something that gives you your elementName
. With the constraint and the elementName
you get:
function Foo<T extends React.HTMLAttributes<HTMLElement>>(
props: T & { elementName: string },
) {
const { elementName, ...otherProps } = props
return React.createElement(elementName, otherProps)
}
Or as a class component:
class Foo<T extends React.HTMLAttributes<HTMLElement>> extends React.Component<
T & { elementName: string }
> {
render() {
const { elementName, ...otherProps } = this.props
return React.createElement(elementName, otherProps)
}
}
Usage works like you seem to expect, though you will have to provide 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 */}
</>
}
Answered By - Alex Wayne
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.