【问题标题】:TypeScript doesn't see defaultProps for functional componentsTypeScript 看不到功能组件的 defaultProps
【发布时间】:2019-03-28 19:18:48
【问题描述】:

我知道这里已经解决了这个问题,但我似乎找不到对我有帮助的解决方案。

我的代码如下:

import * as React from "react";
import inject from "react-jss";

import styles from "./index.styles";

import * as JSS from "jss";

type Colors = "Red" | "White";

interface Props {
  onClick: () => void;
  disabled: boolean;
  classes: JSS.Classes;
  color: Colors;
}

const Button: React.StatelessComponent<Props> = (props): React.ReactElement<any> => {
  const { children, onClick, classes, disabled, color } = props;

  return (
    <button onClick={onClick} disabled={disabled} className={[classes.Main, classes[color]].join(" ")}>
      {children}
    </button>
  );
};

Button.defaultProps = {
  color: "Red",
  disabled: false,
  onClick: () => false,
};

export default inject(styles)(Button);

一切看起来都很好,但是当我在没有 coloronClick 道具的情况下使用这个组件时,我收到了一个错误:

错误:(14, 8) TS2322: Type '{ children: string; onClick: () => 无效; 禁用:布尔值; }' 不可分配给类型 'Pick'。类型 '{ children: 中缺少属性 'color' 细绳; onClick: () => 无效;禁用:布尔值; }'。

我能做什么?我在 TS3.1.1 上。

【问题讨论】:

  • 你使用的是什么版本的 react 和 react 定义?
  • 我认为这可能是一个错误,如果我声明 declare const Button: React.ComponentClass&lt;Props&gt; &amp; { defaultProps: typeof defaultProps } 它可以工作,如果我声明 declare const Button: React.StatelessComponent&lt;Props&gt; &amp; { defaultProps: typeof defaultProps } 它不工作,我希望在两种情况下都会选择 defaultprops
  • 对于直接使用 &lt;Button/&gt;,无状态组件正在使用 TypeScript 的当前 master 为我工作,因此该错误似乎已得到修复。但是,inject HOC 可能没有使用JSX.LibraryManagedAttributes;我还没有研究过。
  • @MattMcCutchen 这是一个在 3.2 中修复的错误,在 3.1 上不起作用 ..
  • 糟糕,再次重复工作。我想要一个更好的方法来避免在 Stack Overflow 上出现这种情况,但我的感觉是试图在元数据上提出它不值得我花精力。

标签: reactjs typescript


【解决方案1】:

这是 3.1 上的 bug。下面的代码适用于 3.2(暂时未发布,您可以使用 npm install typescript@next 进行安装

interface Props {
  onClick: () => void;
  disabled: boolean;
  classes: string;
  color: string;
}
type StatelessComponentArgs<T> = T & { children?: React.ReactNode } // reusable type for the arguments of a stateless compontent
const Button = (props: StatelessComponentArgs<Props>): React.ReactElement<any> => {
  const { children, onClick, classes, disabled, color } = props;

  return (
    <button onClick={onClick} disabled={disabled} >
      {children}
    </button>
  );
};

Button.defaultProps = {
  color: "Red",
  disabled: false,
  onClick: () => false,
};

let d = <Button classes="" color="" onClick={() => { }} disabled={false}></Button>
let d3 = <Button classes="" color="" onClick={() => { }} ></Button>

您的代码也存在问题。如果您将Button 显式键入为React.StatelessComponent&lt;Props&gt;,则defaultProps 将隐含为Partial&lt;Props&gt;,无论您分配给它什么。您需要让编译器推断defaultProps 的类型,如上面的示例所示。

【讨论】:

  • 感谢提香!但是我真的必须包含children 的定义吗?这不应该从某个地方继承/扩展吗?看起来有点乏味。
  • @TomekBuszewski 通常的方法是直接在变量const Button: React.StatelessComponent&lt;Props&gt; 上使用类型。您可以轻松地创建一个辅助类型 type StatelessComponentArgs&lt;T&gt; = T &amp; { children?: React.ReactNode } 并将其用作参数。我将编辑这个的答案。
【解决方案2】:

为了使defaultProps 起作用,defaultProps 对象的实际类型必须存在于Button 的类型上。从 TypeScript 3.1 开始,you can declare a function and assign to its properties 和分配的属性将自动添加到函数的类型中,除非您已经为函数注解了类型,就像您所做的那样。如果我删除类型注释,然后对代码进行必要的更改(指定props 参数的类型并将类型断言添加到默认color 以阻止它扩大),那么我可以成功调用组件:

const Button = (props: Props & { children?: React.ReactNode }): React.ReactElement<any> => {
  const { children, onClick, classes, disabled, color } = props;

  return (
    <button onClick={onClick} disabled={disabled} className={[classes.Main, classes[color]].join(" ")}>
      {children}
    </button>
  );
};
Button.defaultProps = {
  color: "Red" as Colors,
  disabled: false,
  onClick: () => false,
};

const WrappedButton = inject(styles)(Button);
<WrappedButton/>;

删除类型注释的另一种方法是使用包含 defaultProps 对象类型的自定义接口,我相信 Titian Cernicova-Dragomir 正在考虑:

interface Props {
  onClick: () => void;
  disabled: boolean;
  classes: JSS.Classes;
  color: Colors;
  // Something is broken with `inject` without this.
  children?: React.ReactNode;
}

const buttonDefaultProps = {
  color: "Red" as Colors,
  disabled: false,
  onClick: () => false,
};
interface ButtonSFC extends React.SFC<Props> {
  defaultProps: typeof buttonDefaultProps;
}

const Button: ButtonSFC = (props): React.ReactElement<any> => {
  const { children, onClick, classes, disabled, color } = props;

  return (
    <button onClick={onClick} disabled={disabled} className={[classes.Main, classes[color]].join(" ")}>
      {children}
    </button>
  );
};
Button.defaultProps = buttonDefaultProps;

const WrappedButton = inject(styles)(Button);
<WrappedButton/>;

请注意,&lt;Button/&gt; 在 TypeScript 3.1 中给出了一个错误:似乎defaultProps 没有被无状态函数组件所接受。在当前的master 版本的 TypeScript 中,不再出现这个问题(所以我认为不值得调查)(编辑:Titian Cernicova-Dragomir 的答案有错误报告的链接),但有一个不同的问题:@ 987654334@ 给出错误,因为支持调用React.ComponentType 一直是temporarily removed。正在进行修复工作。希望目前,只要您不需要直接调用 Button,您就可以继续使用 TypeScript 3.1。

【讨论】:

    猜你喜欢
    • 2020-01-27
    • 2017-01-21
    • 2017-12-31
    • 2021-03-27
    • 2020-08-14
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多