TypeScript workaround for rest props in React

前端 未结 6 772
迷失自我
迷失自我 2021-02-06 22:50

Updated for TypeScript 2.1

TypeScript 2.1 now supports object spread/rest, so no workarounds are needed anymore!


Original Question

TypeScript s

相关标签:
6条回答
  • 2021-02-06 23:00

    React.HtmlAttributes in the example above is now generic so I needed to extend from React.AnchorHTMLAttributes<HTMLAnchorElement>.

    Example:

    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;
    
    0 讨论(0)
  • 2021-02-06 23:10

    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:

    export function rest(object: any, remove: {[key: string]: any}) {
      let rest = Object.assign({}, object);
      Object.keys(remove).forEach(key => delete rest[key]);
      return rest;
    }
    

    So I can use it like this:

    const {a, b, c} = props;
    const htmlProps = rest(props, {a, b, c});
    

    And once TypeScript supports object rest/spread I can just look for all usages of rest() and simplify it to const {a, b, c, ...htmlProps} = props.

    0 讨论(0)
  • 2021-02-06 23:15

    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:

    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;
        }
    }
    

    Using LinkPropsKeys object, which needs to match the LinkProps, will help you keep the keys between the interface and the runtime lookup synchronized.

    0 讨论(0)
  • 2021-02-06 23:15

    A getter like this could work:

    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" />
    
    0 讨论(0)
  • 2021-02-06 23:16

    It's actually easier than all of the answers above. You just need to follow the example below:

    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
    }
    

    Hope this helps.

    0 讨论(0)
  • 2021-02-06 23:17

    use ...rest

    type ButtonProps = {
        disabled: boolean;
    };
    
    function Button(props: ButtonProps): JSX.Element {
        const {disabled = false, ...rest} = props;
    ...
    return (
        <button disabled={disabled} {...rest}>
    ....

    0 讨论(0)
提交回复
热议问题