使用 TypeScript 的 React 组件中的默认属性值

新手上路,请多包涵

我不知道如何使用 Typescript 为我的组件设置默认属性值。

这是源代码:

 class PageState
{
}

export class PageProps
{
    foo: string = "bar";
}

export class PageComponent extends React.Component<PageProps, PageState>
{
    public render(): JSX.Element
    {
        return (
            <span>Hello, world</span>
        );
    }
}

当我尝试使用这样的组件时:

 ReactDOM.render(<PageComponent />, document.getElementById("page"));

我收到一条错误消息,提示缺少属性 foo 。我想使用默认值。我也尝试在组件内部使用 static defaultProps = ... ,但我怀疑它没有效果。

 src/typescript/main.tsx(8,17): error TS2324: Property 'foo' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes<PageComponent> & PageProps & { children?: ReactEle...'.

如何使用默认属性值?我公司使用的许多 JS 组件都依赖于它们,不使用它们不是一种选择。

原文由 Tom 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.5k
2 个回答

带有类组件的默认道具

使用 static defaultProps 是正确的。您还应该为道具和状态使用接口,而不是类。

2018/12/1 更新:TypeScript 随着时间的推移改进了与 defaultProps 相关的类型检查。继续阅读最新和最有用的用法,直至旧用法和问题。

对于 TypeScript 3.0 及更高版本

TypeScript 专门 添加了对 defaultProps 的支持,以使类型检查按您的预期工作。例子:

 interface PageProps {
  foo: string;
  bar: string;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, { this.props.foo.toUpperCase() }</span>
        );
    }
}

无需传递 foo 属性即可渲染和编译:

 <PageComponent bar={ "hello" } />

注意:

  • foo 标记为可选(即 foo?: string ),即使它不是 JSX 属性所必需的。标记为可选意味着它可能是 undefined ,但实际上它永远不会是 undefined 因为 defaultProps 提供了默认值。可以将其想象为类似于如何 将函数参数标记为可选或使用默认值,但不能同时使用两者,但两者都意味着调用不需要指定 value 。 TypeScript 3.0+ 以类似的方式处理 defaultProps ,这对 React 用户来说真的很酷!
  • defaultProps 没有明确的类型注释。编译器推断并使用它的类型来确定需要哪些 JSX 属性。您可以使用 defaultProps: Pick<PageProps, "foo"> 来确保 defaultProps 匹配 PageProps 的子集。 此处解释了 有关此警告的更多信息。
  • 这需要 @types/react 版本 16.4.11 才能正常工作。

对于 TypeScript 2.1 到 3.0

在 TypeScript 3.0 实现对 defaultProps 的编译器支持之前,您仍然可以使用它,并且它在运行时与 React 100% 工作,但由于 TypeScript 在检查 JSX 属性时只考虑道具,因此您必须标记道具带有 ? 的默认值是可选的。例子:

 interface PageProps {
    foo?: string;
    bar: number;
}

export class PageComponent extends React.Component<PageProps, {}> {
    public static defaultProps: Partial<PageProps> = {
        foo: "default"
    };

    public render(): JSX.Element {
        return (
            <span>Hello, world</span>
        );
    }
}

注意:

  • Partial<> 注释 defaultProps 是个好主意,这样它就可以对你的 props 进行类型检查,但你不必为每个必需的属性提供默认值,这样就不会有意义,因为必需的属性永远不需要默认值。
  • When using strictNullChecks the value of this.props.foo will be possibly undefined and require a non-null assertion (ie this.props.foo! ) or type-guard (即 if (this.props.foo) ... )删除 undefined 。这很烦人,因为默认的 prop 值意味着它实际上永远不会未定义,但 TS 不理解这个流程。这是 TS 3.0 增加对 defaultProps 的明确支持的主要原因之一。

在 TypeScript 2.1 之前

这同样适用,但您没有 Partial 类型,所以只需省略 Partial<> 并为所有必需的道具提供默认值(即使这些默认值永远不会被使用)或省略完全显式类型注释。

带有 功能组件 的默认道具

You can use defaultProps on function components as well, but you have to type your function to the FunctionComponent ( StatelessComponent in @types/react before version 16.7.2 ) 接口,以便 TypeScript 了解 defaultProps 函数:

 interface PageProps {
  foo?: string;
  bar: number;
}

const PageComponent: FunctionComponent<PageProps> = (props) => {
  return (
    <span>Hello, {props.foo}, {props.bar}</span>
  );
};

PageComponent.defaultProps = {
  foo: "default"
};

请注意,您不必在任何地方使用 Partial<PageProps> 因为 FunctionComponent.defaultProps 已在 TS 2.1+ 中指定为部分。

另一个不错的选择(这是我使用的)是解构您的 props 参数并直接分配默认值:

 const PageComponent: FunctionComponent<PageProps> = ({foo = "default", bar}) => {
  return (
    <span>Hello, {foo}, {bar}</span>
  );
};

那么你根本不需要 defaultProps !请注意,如果您 确实 在函数组件上提供 defaultProps 它将优先于默认参数值,因为 React 将始终显式传递 defaultProps 值(因此参数永远不会未定义,因此从不使用默认参数。)所以你会使用一个或另一个,而不是两者。

原文由 Aaron Beall 发布,翻译遵循 CC BY-SA 4.0 许可协议

在 Typescript 2.1+ 中,使用 Partial < T > 而不是将接口属性设为可选。

 export interface Props {
    obj: Model,
    a: boolean
    b: boolean
}

public static defaultProps: Partial<Props> = {
    a: true
};

原文由 Learner 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进