【问题标题】:Typing defaulted passthrough props in React with TypeScript在 React 中使用 TypeScript 键入默认的直通属性
【发布时间】:2020-01-28 13:11:16
【问题描述】:

React 组件通常会接受一些 props 并将其传递给它们的子组件。如果由于孩子的defaultProps 指定了孩子身上的一个或多个道具是可选的,那么如何为正确接受自己和孩子道具的父母定义typeinterface

考虑以下说明性示例:

interface ParagraphProps {
  body: string,
  imgSrc: string,
}

interface SectionProps extends ParagraphProps {
  title: string,
}

class Paragraph extends React.Component<ParagraphProps> {
  static defaultProps = {
    imgSrc: '../images/section-break.jpg',
  };

  render() {
    const { body, imgSrc } = this.props;

    return (
      <p>{body}</p>
      {!!imgSrc && <img src={imgSrc}>}
    );
  }
}

class Section extends React.Component<SectionProps> {
  render() {
    const { title, ...rest } = this.props;

    return (
      <section>
        <h1>{title}</h1>
        <Paragraph {...rest}>
      </section>
    );
  }
}

现在,声明 &lt;Section title='T' body='B'&gt; 将导致错误:

类型 [...] 中缺少属性“imgSrc”

如果我们改为为 Section 定义 props,如下所示:

interface SectionProps {
  title: string,
}

type FullSectionProps = Partial<SectionProps & PartialProps>;

然后我们发现现在titlebody是可选的,这不是我们想要的。

在剩余 DRY 的同时,我应该如何指定 Section 的 props 以规定 titlebody 是必需的,imgSrc 是可选的?

【问题讨论】:

    标签: reactjs typescript typescript3.0


    【解决方案1】:

    由于ParagraphProps 接口对应于Paragraph 组件,因此保持这些“对齐”可能是有意义的。您知道imgSrc 有一个默认值,因此在界面中将其标记为可选是有意义的,因为no-one 使用Paragraph 组件(不仅是Section 组件)是需要传入imgSrc

    interface ParagraphProps {
      body: string,
      imgSrc?: string,
    }
    

    如果不是Paragraph 组件的所有用户都需要传入imgSrcSection 组件除外),那么将默认值移动到@987654332 可能更有意义@组件为imgSrc

    最后,如果您想让它更具动态性,您可以执行以下操作,尽管在此示例中它可能比必要的更复杂。

    // Only needed if not 3.5+ (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-5.html#the-omit-helper-type)
    type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
    
    interface ParagraphProps {
      body: string;
      imgSrc: string;
    }
    
    type PropsWithDefaults = keyof typeof Paragraph.defaultProps;
    type TransformedProps = Partial<Pick<ParagraphProps, PropsWithDefaults>> &
      Omit<ParagraphProps, PropsWithDefaults>;
    
    interface SectionProps extends TransformedProps {
      title: string;
    }
    
    class Section extends React.Component<SectionProps> {
      render() {
        const { title, ...rest } = this.props;
    
        return <Paragraph {...rest} />;
      }
    }
    
    class Paragraph extends React.Component<ParagraphProps> {
      static defaultProps = {
        imgSrc: "../images/section-break.jpg"
      };
    
      render() {
        return null;
      }
    }
    
    <Section body="foo" title="baz" />
    <Section body="foo" title="baz" imgSrc="override" />
    

    这里,TransformedProps 类型包含来自ParagraphProps 的所有道具,其中Paragraph.defaultProps 中的道具通过使用Partial 成为可选的。有关PickOmit 如何形成此结构的更多详细信息,请参阅Advanced Types documentation

    【讨论】:

      猜你喜欢
      • 2016-09-13
      • 2019-06-30
      • 1970-01-01
      • 2021-11-04
      • 2017-12-14
      • 2016-07-10
      • 2021-10-29
      • 1970-01-01
      • 2021-05-19
      相关资源
      最近更新 更多