TypeScript 2.1 now supports object spread/rest,因此不再需要解决方法了!
TypeScript支持JSX spread attributes,它在React中常用于将HTML属性从组件传递到呈现的HTML元素:
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" />
然而,React引入了warning if you pass any unknown props to an HTML element。上面的示例将生成一个React运行时警告,textToDisplay
是<a>
的未知支柱。针对此示例的案例的建议解决方案是使用object rest properties来提取自定义道具并将其余部分用于JSX传播属性:
const {textToDisplay, ...htmlProps} = this.props;
return (
<a {...htmlProps}>{textToDisplay}</a>
);
但是TypeScript还不支持这种语法。我希望有一天we will be able to do this in TypeScript。( 更新 :TS 2.1 now supports object spread/rest!为什么还在读这个? )与此同时,有哪些解决方法?我正在寻找一种不会影响类型安全并且发现它非常困难的解决方案。例如,我可以这样做:
const customProps = ["textDoDisplay", "otherCustomProp", "etc"];
const htmlProps:HTMLAttributes = Object.assign({}, this.props);
customProps.forEach(prop => delete htmlProps[prop]);
但是这需要使用未针对实际道具验证的字符串属性名称,因此容易出现拼写错误和错误的IDE支持。我们有更好的方法吗?
答案 0 :(得分:4)
您可能无法避免使用this.props
属性的子集创建新对象,但您可以使用类型安全来执行此操作。
例如:
interface LinkProps {
textToDisplay: string;
}
const LinkPropsKeys: LinkProps = { textToDisplay: "" };
class Link extends React.Component<LinkProps & React.HTMLAttributes, {}> {
public render(): JSX.Element {
return (
<a { ...this.getHtmlProps() }>{ this.props.textToDisplay }</a>
);
}
private getHtmlProps(): React.HTMLAttributes {
let htmlProps = {} as React.HTMLAttributes;
for (let key in this.props) {
if (!(LinkPropsKeys as any)[key]) {
htmlProps[key] = this.props[key];
}
}
return htmlProps;
}
}
使用LinkPropsKeys
对象(需要匹配LinkProps
)将帮助您保持接口和运行时查找之间的密钥同步。
答案 1 :(得分:1)
我接受了Nitzen Tomer的回答,因为这是我想要的基本想法。
作为一个更通用的解决方案,这就是我最终的目标:
export function rest(object: any, remove: {[key: string]: any}) {
let rest = Object.assign({}, object);
Object.keys(remove).forEach(key => delete rest[key]);
return rest;
}
所以我可以这样使用它:
const {a, b, c} = props;
const htmlProps = rest(props, {a, b, c});
一旦TypeScript支持对象休息/传播,我就可以查找rest()
的所有用法并将其简化为const {a, b, c, ...htmlProps} = props
。
答案 2 :(得分:1)
实际上,它比上面的所有答案都容易。您只需要遵循以下示例:
type Props = {
id: number,
name: string;
// All other props
[x:string]: any;
}
const MyComponent:React.FC<Props> = props => {
// Any property passed to the component will be accessible here
}
希望这会有所帮助。
答案 3 :(得分:1)
使用...rest
type ButtonProps = {
disabled: boolean;
};
function Button(props: ButtonProps): JSX.Element {
const {disabled = false, ...rest} = props;
...
return (
<button disabled={disabled} {...rest}>
....
答案 4 :(得分:0)
上面示例中的React.HtmlAttributes现在是通用的,因此我需要从React.AnchorHTMLAttributes<HTMLAnchorElement>
扩展。
示例:
import React from 'react';
type AClickEvent = React.MouseEvent<HTMLAnchorElement>;
interface LinkPropTypes extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
to: string;
onClick?: (x: AClickEvent) => void;
}
class Link extends React.Component<LinkPropTypes> {
public static defaultProps: LinkPropTypes = {
to: '',
onClick: null,
};
private handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
...
event.preventDefault();
history.push(this.props.to);
};
public render() {
const { to, children, ...props } = this.props;
return (
<a href={to} {...props} onClick={this.handleClick}>
{children}
</a>
);
}
}
export default Link;
答案 5 :(得分:0)
这样的吸气剂可以工作:
class Link extends React.Component<{
textToDisplay: string;
} & React.HTMLAttributes<HTMLDivElement>> {
static propTypes = {
textToDisplay: PropTypes.string;
}
private get HtmlProps(): React.HTMLAttributes<HTMLAnchorElement> {
return Object.fromEntries(
Object.entries(this.props)
.filter(([key]) => !Object.keys(Link.propTypes).includes(key))
);
}
public render():JSX.Element {
return (
<a {...this.HtmlProps}>
{this.props.textToDisplay}
</a>
);
}
}
<Link textToDisplay="Search" href="http://google.com" />