小编典典

用于React中其余道具的TypeScript解决方法

reactjs

更新为TypeScript 2.1

TypeScript
2.1现在支持对象散布/休息
,因此不再需要任何解决方法!


原始问题

TypeScript支持JSX扩展属性,该属性通常在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" />

但是,如果您将任何未知的prop传递给HTML元素,React都会发出警告。上面的示例将产生一个React运行时警告,它textToDisplay是的未知属性<a>。对于类似此示例的情况,建议的解决方案是使用对象其余属性提取您的自定义道具,并将其余用于JSX传播属性:

const {textToDisplay, ...htmlProps} = this.props;
return (
  <a {...htmlProps}>{textToDisplay}</a>
);

但是TypeScript尚不支持此语法。
我知道希望有一天我们能够在TypeScript中做到这一点

更新TS
2.1现在支持对象散布/静止
!为什么仍要阅读此内容?)同时有一些解决方法?我正在寻找一种不会损害类型安全性的解决方案,并且发现它出奇的困难。例如,我可以这样做:

const customProps = ["textDoDisplay", "otherCustomProp", "etc"];
const htmlProps:HTMLAttributes = Object.assign({}, this.props);
customProps.forEach(prop => delete htmlProps[prop]);

但是,这需要使用未经实际道具验证的字符串属性名称,因此容易产生错字和对IDE的不良支持。有没有更好的方法可以做到这一点?


阅读 292

收藏
2020-07-22

共1个答案

小编典典

您可能无法避免使用的属性的子集创建新对象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需要与匹配的object LinkProps可以帮助您使接口和运行时查找之间的键保持同步。

2020-07-22