【问题标题】:React with TypeScript - define defaultProps in stateless function与 TypeScript 反应 - 在无状态函数中定义 defaultProps
【发布时间】:2016-09-12 17:20:48
【问题描述】:

我正在使用带有 TypeScript 的 React,并且我创建了无状态函数。为了便于阅读,我从示例中删除了无用的代码。

interface CenterBoxProps extends React.Props<CenterBoxProps> {
    minHeight?: number;
}

export const CenterBox = (props: CenterBoxProps) => {
    const minHeight = props.minHeight || 250;
    const style = {
        minHeight: minHeight
    };
    return <div style={style}>Example div</div>;
};

一切都很好,这段代码工作正常。但是我的问题是:如何为CenterBox 组件定义defaultProps

正如react docs中提到的:

(...) 它们是输入的纯函数变换,零 样板。但是,您仍然可以指定 .propTypes 和 .defaultProps 通过将它们设置为函数的属性,就像 您可以将它们设置在 ES6 类上。 (...)

应该很简单:

CenterBox.defaultProps = {
    minHeight: 250
}

但是这段代码会产生 TSLint 错误:error TS2339: Property 'defaultProps' does not exist on type '(props: CenterBoxProps) =&gt; Element'.

再说一遍:如何在上面的堆栈(React + TypeScript)中正确定义defaultProps

【问题讨论】:

    标签: reactjs typescript


    【解决方案1】:

    在寻找解决方案 2 小时后...它正在工作

    如果你想定义defaultProps,你的箭头函数应该是这样的:

    export const CenterBox: React.SFC<CenterBoxProps> = props => {
        (...)
    };
    

    然后你可以定义像这样的道具:

    CenterBox.defaultProps = { someProp: true }
    

    注意React.SFCReact.StatelessComponent 的别名。

    我希望这个问题(和答案)对某人有所帮助。确保你已经安装了最新的 React 类型。

    【讨论】:

    • 你能添加一个更具体的例子来说明你是如何让 defaultProps 工作的吗?谢谢:D
    • 这确实有效。谢谢@Jurosh,您介意将此(您的)答案标记为正确吗?
    【解决方案2】:

    我相信比 React 文档中描述的更好的方法是简单地使用 Javascript / Typescript 默认参数。

    这里有答案:https://stackoverflow.com/a/54569933/484190 但为了方便起见,这里有一个例子:

    import React, { FC } from "react";
    
    interface CompProps {
      x?: number;
      y?: number;
    }
    
    const Comp: FC<CompProps> = ({ x = 10, y = 20 }) => {
      return <div>{x}, {y}</div>;
    }
    
    export default Comp;
    

    这将使 Typescript 知道您不必提供该道具,并且它永远不会在您的组件中“未定义”

    【讨论】:

    • 这太完美了!
    • 不幸的是你不会在 react 开发工具中看到那些默认的 props..
    • @pete otaqui 你用 InferProps 和 PropTypes 试过了吗?我到处看了看,但没有找到告诉 TS 值不是未定义的方法
    • @OrBachar 你知道为什么在开发工具中看不到 defaultProps 吗?有没有办法让开发工具来展示它们?
    【解决方案3】:

    下面是有状态函数的工作原理,以防其他人偶然发现。 关键是将 defaultProps 声明为静态变量。

    interface IBoxProps extends React.Props<IBoxProps> {
        x?: number;
        y?: number;
        height?: number;
        width?: number;
    }
    
    interface IBoxState {
        visible?: boolean;
    }
    
    export default class DrawBox extends React.Component<IBoxProps, IBoxState> {
        static defaultProps: IBoxProps;
    
        constructor(props: IBoxProps) {
            super(props);
        }
        ...
    }
    
    DrawBox.defaultProps = {
        x=0;
        y=0;
        height=10;
        weight=10;
    };
    

    【讨论】:

    • 我知道这有点晚了。当我尝试继承 DrawBox 类并使用“class SubDrawBox extends DrawBox”创建子类时,我收到错误 DrawBox 不是通用的。我该如何解决这个问题?
    • 请您尝试回答我的问题 - stackoverflow.com/questions/50068412
    • 这个答案与问题无关。它是一个类组件,而不是一个无状态的功能组件。
    • 这对我有帮助,因为我使用的是 Class 组件。谢谢你。作为旁注,您可以像这样声明defaultPropsstatic defaultProps: Partial&lt;IBoxProps&gt;,以防您不想为每个属性提供默认值。
    【解决方案4】:

    对于功能组件,从 React 16.7.0 开始,'React.SFC' 类型已被弃用,取而代之的是 'React.FC'。

    示例

    type TFuncComp = React.FC<{ text: string }>
    
    const FuncComp: TFuncComp = props => <strong>{props.text}</strong>
    
    FuncComp.defaultProps = { text: 'Empty Text' }
    

    Deprecation Warning in Source

    FC (FunctionalComponent) Type in Source

    【讨论】:

      【解决方案5】:

      使用 React.FC 在函数组件中键入默认 props 可能会导致错误类型错误:

         type Props = {
           required: string,
         } & typeof defaultProps;
      
         const defaultProps = {
           optDefault: 'optDefault'
         };
      
         const MyComponent: React.FC<Props> = (props: Props) => (
           <ul>
             <li>required: {props.required}</li>
             <li>optDefault: {props.optDefault}</li>
           </ul>
         )
         MyComponent.defaultProps = defaultProps;
      
      
         ReactDOM.render(
           <div>
             <MyComponent
               required='required'
               optDefault='over written'
             />
             <MyComponent   /* type error  <---- false type error */
               required='required'
             />
           </div>,
           document.getElementById('app')
         );
      

      错误:

      [tsserver 2741] Property 'optDefault' is missing in type '{ required: string; }' but required in type '{ optDefault: string; }'. [E]
      

      提出的另一种解决方案是使用Javascript自己的默认函数参数:

      type Props = {
        required: string,
        optDefault?: string
      }
      
      const MyComponent:  React.FC<Props> = ({
        required,
        optDefault='default'
      }: Props) => (
        <ul>
          <li>required: {required}</li>
          <li>optDefault: {optDefault}</li>
        </ul>
      )
      
      ReactDOM.render(
        <div>
          <MyComponent
            required='required'
            optDefault='over written'
          />
          <MyComponent
            required='required'
          />
        </div>,
        document.getElementById('app')
      );
      

      但是这个解决方案的问题是,如果你忘记提供默认值,就会导致运行时错误:

      const MyComponent: React.FC<Props> = ({
        required,
        optDefault //='optDefault' //<--- if you forgot to provide default
      }: Props) => (
        <ul>
          <li>required: {required}</li>
          <li>optDefault: {optDefault}</li> {/* <-- result in bug */}
        </ul>
      )
      

      更好的解决方案是根本不使用 React.FC,只依赖 Typescript 类型推断:

      type Props = {
        required: string,
      } & typeof defaultProps;
      
      const defaultProps = {
        optDefault: 'optDefault'
      };
      
      const MyComponent = (props: Props) => (
        <ul>
          <li>required: {props.required}</li>
          <li>optDefault: {props.optDefault}</li>
        </ul>
      )
      MyComponent.defaultProps = defaultProps
      
      
      ReactDOM.render(
        <div>
          <MyComponent
            required='required'
            optDefault='over written'
          />
          <MyComponent
            required='required'
          />
        </div>,
        document.getElementById('app')
      );
      

      【讨论】:

      • 完全不使用 React.FC 确实对我来说效果更好,谢谢!
      • 是的,我同意这个答案,当尝试使用 styled-component 模块像默认 Typescript 类型接口一样包装 JSX.Element 时出现另一个问题
      【解决方案6】:

      你可以把它放在你的组件中

      static defaultProps: any;
      

      【讨论】:

        【解决方案7】:

        对我来说最简单的是直接在 defaultProps 中定义(部分)默认值:

        export default class TSError extends React.Component<ITSErrorProps, {}> {
          private static defaultProps: Partial<ITSErrorProps> = {
            fullPage: true,
            controlClick: true,
            doubleClick: true
          };
        
        ...
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-21
          • 2017-01-21
          • 2018-04-09
          • 2017-02-19
          • 2018-05-06
          • 1970-01-01
          • 1970-01-01
          • 2020-08-20
          相关资源
          最近更新 更多