代码之家  ›  专栏  ›  技术社区  ›  Ickerday Argus Malware

TS+React-应该导出道具接口吗?

  •  0
  • Ickerday Argus Malware  · 技术社区  · 3 年前

    我没有在任何地方找到任何关于这方面的信息,但我对最佳实践很好奇。

    在我的工作项目中,我目前正在定义我的道具界面,如下所示:

    export interface ExampleComponentProps {
      readonly firstExampleProp: string;
      readonly secondExampleProp: number
    }
    

    export -正在刷新接口或 readonly -ing成员在编译或运行时会产生性能开销吗? 除了可读性和明确性之外,这样做还有什么好处吗?

    0 回复  |  直到 3 年前
        1
  •  5
  •   Martin Devillers    3 年前
    • export -ing道具是一个很好的实践,因为它允许更高级的用例,比如在另一个系统中包装组件。请参见下面的示例。
    • 添加 readonly 我觉得每一处房产都更像是个人喜好。是的,道具应该 从不 在一个组件中被覆盖,但同时这是非常常见的知识和添加 只读 任何地方都可能有点多余。
    import { ExampleComponent, ExampleComponentProps } from "./ExampleComponent";
    
    type WrappedExampleComponentProps = {
      newProperty: string;
    } & ExampleComponentProps; 
    // I wouldn't be able to this if I weren't able to import ExampleComponentProps
    
    export const WrappedExampleComponent = (props: WrappedExampleComponentProps ) => {
      const { newProperty, ...otherProps } = props;
      return (
          <ExampleComponent {...otherProps } />
          <SideComponent newProperty={newProperty} />
      );
    };
    

    在性能方面:肯定有 运行时性能会受到影响,因为运行时不存在任何类型脚本构造。在编译时,我想说这些更改对性能的影响可以忽略不计,并且超过了它的优点(例如可扩展性)。

        2
  •  2
  •   Sam McElligott    3 年前

    太长,读不下去了是的,就像 Martin's Answer 在美国,最好的做法是导出道具,这样任何包装器组件都可以使用它们。在我看来,readonly标志是不必要的,因为道具应该始终是只读的(解释如下),性能不是问题。

    出口

    详细回答: 回答问题 export -作为问题的一部分,你绝对应该导出道具界面。拿 Material UI (梅)例如;打字惯例 README 从他们的GitHub州:

    • 从{component}类导出接口{component name}类。ts和添加注释以生成api文档(对于内部组件,可以公开或不公开类,但不需要注释)
    • 导出接口{ComponentName}Props
    • 始终从组件文件导出道具接口(使用接口而不是类型)

    第二和第三部分说,MUI开发人员编写的每个公共组件文件都应该导出道具。在编写其道具扩展了MUI组件道具的组件时,以及在编写自己的组件时,我利用了这一点。仅此一点就足以说服您导出所有道具的接口。唯一可行的理由是,如果风格指南出于某种原因明确地这么说。

    下面的代码是我目前正在处理的React+TS站点中的组件定义。

    import type {ButtonProps} from "@mui/material/Button";
    import { ThrottleClasses } from "@/store/throttle";
    
    /**
     * Props structure for {@link RequestButton}
     */
    export interface RequestButtonProps
      extends Omit<ButtonProps, "title" | "variant"> {
      /**
       * Whether or not the form adjacent to this element is valid.
       */
      valid: boolean;
      /**
       * The name of a value in the throttle store to compare against
       * to decide if the request can be sent.
       */
      throttle?: string;
      /**
       * The `isLoading` property returned from an RTK query or mutation.
       */
      isLoading?: boolean;
      /**
       * The `isError` property returned from an RTK query or mutation.
       */
      isError?: boolean;
      /**
       * The action phrase which is displayed on the button's tooltip.
       */
      title?: React.ReactNode;
      /**
       * The button's style type, analogous to those defined in {@link ButtonProps}.
       */
      variant?: "contained" | "text" | "outlined";
    }
    
    /**
     * A button to be used when send requests to the backend.
     * This component also listens to the throttle state in 
     * order to prevent excessive requests if necessary.
     * This can be done by dispatching a throttle action when this button is clicked,
     * and passing the corresponding {@link ThrottleClasses} property to this.
     * @props {@link FormSubmitProps}
     * @component
     */
    export const RequestButton: React.FC<RequestButtonProps> = ({
      valid,
      children,
      throttle,
      isLoading,
      isError = false,
      title = children,
      variant = "contained",
      ...props
    }) => {
    ...
    

    导出道具界面的另一个鲜为人知的原因(至少我没听说过太多)是自动生成文档。如果您回顾一下MUI报价的第二部分,它还提到“为生成api文档添加注释”。在上面的代码中可以看到一个例子,其中每个属性都有一个简短的解释。

    我使用了一个叫做 TypeDoc 用于生成文档。它所做的是研究出口和伴随的 JSDoc 样式注释,用双星号表示(JSDoc是JavaScript的类似工具),并使用它们生成可浏览的静态HTML站点。我之所以提到这一点,是因为为了让它发挥作用,你必须导出你想要记录的项目,所以如果你以后决定使用它,它可能会派上用场。此外,即使你不使用这个工具,文本编辑器 VSCode 当你将鼠标悬停在属性上时,甚至在其他文件中,使用这些注释来提供上下文。我个人认为,当我记不起某个属性的用途时,这些注释非常有用。

    VSCode Example

    只读属性

    关于 readonly 塔格,我完全同意马丁的观点;重新分配道具是非常糟糕的做法,这使得 只读 标记冗余。这在本文中得到了很好的解释 answer 关于重新分配道具。

    作为回应,你不应该试图改变道具。属性是从父组件传递的内容。如果要更改属性,必须转到父组件并更改传递的内容。

    表演

    在性能方面,它有 没有开销 在运行时,因为所有的TypeScript定义(类型、接口等)由TypeScript编译器删除,但不在输出文件中。在编译过程中,可能会有一些 轻微的 开销,但在实际应用程序中,这不会超过几毫秒。