Updated for TypeScript 2.1
TypeScript 2.1 now supports object spread/rest, so no workarounds are needed anymore!
Original Question
TypeScript supports JSX spread attributes which is commonly used in React to pass HTML attributes from a component to a rendered HTML element:
interface LinkProps extends React.HTMLAttributes {
textToDisplay: string;
}
class Link extends React.Component<LinkProps, {}> {
public render():JSX.Element {
return (
<a {...this.props}>{this.props.textToDisplay}</a>
);
}
}
<Link textToDisplay="Search" href="http://google.com" />
However, React introduced a warning if you pass any unknown props to an HTML element. The above example would produce a React runtime warning that textToDisplay
is an unknown prop of <a>
. The suggested solution for a case like this example is to use object rest properties to extract out your custom props and use the rest for the JSX spread attributes:
const {textToDisplay, ...htmlProps} = this.props;
return (
<a {...htmlProps}>{textToDisplay}</a>
);
But TypeScript does not yet support this syntax. I know that hopefully some day we will be able to do this in TypeScript. (Update: TS 2.1 now supports object spread/rest! Why are you still reading this??) In the meantime what are some workarounds? I'm looking for a solution that doesn't compromise type-safety and finding it surprisingly difficult. For example I could do this:
const customProps = ["textDoDisplay", "otherCustomProp", "etc"];
const htmlProps:HTMLAttributes = Object.assign({}, this.props);
customProps.forEach(prop => delete htmlProps[prop]);
But this requires the use of string property names that are not validated against the actual props and thus prone to typos and bad IDE support. Is there a better way we can do this?
It's actually easier than all of the answers above. You just need to follow the example below:
Hope this helps.
A getter like this could work:
You probably can't avoid creating a new object with a subset of the properties of
this.props
, but you can do that with type safety.For example:
Using
LinkPropsKeys
object, which needs to match theLinkProps
, will help you keep the keys between the interface and the runtime lookup synchronized.React.HtmlAttributes in the example above is now generic so I needed to extend from
React.AnchorHTMLAttributes<HTMLAnchorElement>
.Example:
I've accepted Nitzen Tomer's answer because it was the basic idea I was going for.
As a more generalized solution this is what I ended up going with:
So I can use it like this:
And once TypeScript supports object rest/spread I can just look for all usages of
rest()
and simplify it toconst {a, b, c, ...htmlProps} = props
.