与 TypeScript 反应 - 在无状态函数中定义 defaultProps

Posted

技术标签:

【中文标题】与 TypeScript 反应 - 在无状态函数中定义 defaultProps【英文标题】:React with TypeScript - define defaultProps in stateless function 【发布时间】: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

【问题讨论】:

【参考方案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://***.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 不是通用的。我该如何解决这个问题? 请您尝试回答我的问题 - ***.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
  ;

...


【讨论】:

以上是关于与 TypeScript 反应 - 在无状态函数中定义 defaultProps的主要内容,如果未能解决你的问题,请参考以下文章

与 Typescript 反应:“never[]”类型的参数不可分配给“StateProperties |”类型的参数(() => 状态属性)'

在无状态组件中类型检查 styled-components 道具

如何在嵌套函数中在无状态函数中设置状态?

在无状态组件内传递函数不起作用

在无状态 Node.js 应用程序中调度函数调用

允许 typescript 编译器仅在一个反应​​状态属性上调用 setState